diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml
index 0d8cc45a9..2257b57de 100644
--- a/.github/workflows/ruby.yml
+++ b/.github/workflows/ruby.yml
@@ -15,7 +15,7 @@ jobs:
ruby: ["3.2", "3.3"]
bootstrap_version: ["~> 4.0"]
blacklight_version: ["~> 8.0"]
- additional_engine_cart_rails_options: ["-a propshaft -j esbuild"]
+ additional_engine_cart_rails_options: ["-a propshaft -j importmap"]
additional_name: [""]
include:
- rails_version: "~> 7.2"
@@ -28,6 +28,18 @@ jobs:
blacklight_version: "~> 8.0"
bootstrap_version: "~> 4.0"
additional_name: Rails 7.1
+ - rails_version: "~> 7.1.4"
+ ruby: "3.2"
+ blacklight_version: "~> 8.0"
+ bootstrap_version: "~> 4.0"
+ additional_engine_cart_rails_options: "-a propshaft -j esbuild"
+ additional_name: "JS bundling (esbuild) Bootstrap 4"
+ - rails_version: "~> 7.2"
+ ruby: "3.3"
+ blacklight_version: "~> 8.0"
+ bootstrap_version: "~> 5.0"
+ additional_engine_cart_rails_options: "-a propshaft -j esbuild"
+ additional_name: "JS bundling (esbuild) Bootstrap 5"
env:
RAILS_VERSION: ${{ matrix.rails_version }}
BLACKLIGHT_VERSION: ${{ matrix.blacklight_version }}
diff --git a/README.md b/README.md
index 59cdbbdd1..e5b842856 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,13 @@ Read more about what Spotlight is, our motivations for creating it, and how to i
## Installation
-To bootstrap a new Rails application:
+To bootstrap a new Rails application using [importmap-rails](https://github.com/rails/importmap-rails):
+
+```
+$ SKIP_TRANSLATION=1 rails new app-name -m https://raw.githubusercontent.com/projectblacklight/spotlight/main/template.rb -a propshaft -j importmap
+```
+
+or using [jsbundling-rails](https://github.com/rails/jsbundling-rails) with [esbuild](https://esbuild.github.io/):
```
$ SKIP_TRANSLATION=1 rails new app-name -m https://raw.githubusercontent.com/projectblacklight/spotlight/main/template.rb -a propshaft -j esbuild
diff --git a/Rakefile b/Rakefile
index 76cef8a2c..1c79a7d3d 100644
--- a/Rakefile
+++ b/Rakefile
@@ -33,7 +33,7 @@ require 'spotlight/version'
# Build with our opinionated defaults if none are provided.
rails_options = ENV.fetch('ENGINE_CART_RAILS_OPTIONS', '')
rails_options = "#{rails_options} -a propshaft" unless rails_options.match?(/-a\s|--asset-pipeline/)
-rails_options = "#{rails_options} -j esbuild" unless rails_options.match?(/-j\s|--javascript/)
+rails_options = "#{rails_options} -j importmap" unless rails_options.match?(/-j\s|--javascript/)
ENV['ENGINE_CART_RAILS_OPTIONS'] = rails_options
task ci: ['engine_cart:generate'] do
diff --git a/app/assets/javascripts/spotlight/spotlight.esm.js b/app/assets/javascripts/spotlight/spotlight.esm.js
index 41df9ca46..f86009335 100644
--- a/app/assets/javascripts/spotlight/spotlight.esm.js
+++ b/app/assets/javascripts/spotlight/spotlight.esm.js
@@ -1,6 +1,4 @@
-import require$$0 from 'leaflet';
import Clipboard from 'clipboard';
-import Blacklight from 'blacklight-frontend';
import SirTrevor from 'sir-trevor';
// Includes an unreleased RTL support pull request: https://github.com/ganlanyuan/tiny-slider/pull/658
@@ -3380,3561 +3378,6 @@ class UserIndex {
}
}
-/*!
- * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
- * Dual-licensed under the BSD or MIT licenses
- */
-(function($, window, document, undefined$1)
-{
- var hasTouch = 'ontouchstart' in window;
-
- /**
- * Detect CSS pointer-events property
- * events are normally disabled on the dragging element to avoid conflicts
- * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
- */
- var hasPointerEvents = (function()
- {
- var el = document.createElement('div'),
- docEl = document.documentElement;
- if (!('pointerEvents' in el.style)) {
- return false;
- }
- el.style.pointerEvents = 'auto';
- el.style.pointerEvents = 'x';
- docEl.appendChild(el);
- var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
- docEl.removeChild(el);
- return !!supports;
- })();
-
- var eStart = hasTouch ? 'touchstart' : 'mousedown',
- eMove = hasTouch ? 'touchmove' : 'mousemove',
- eEnd = hasTouch ? 'touchend' : 'mouseup',
- eCancel = hasTouch ? 'touchcancel' : 'mouseup';
-
- var defaults = {
- listNodeName : 'ol',
- itemNodeName : 'li',
- rootClass : 'dd',
- listClass : 'dd-list',
- itemClass : 'dd-item',
- dragClass : 'dd-dragel',
- handleClass : 'dd-handle',
- collapsedClass : 'dd-collapsed',
- placeClass : 'dd-placeholder',
- noDragClass : 'dd-nodrag',
- noChildrenClass : 'dd-nochildren',
- emptyClass : 'dd-empty',
- expandBtnHTML : '',
- collapseBtnHTML : '',
- group : 0,
- maxDepth : 5,
- threshold : 20,
- reject : [],
- //method for call when an item has been successfully dropped
- //method has 1 argument in which sends an object containing all
- //necessary details
- dropCallback : null,
- // When a node is dragged it is moved to its new location.
- // You can set the next option to true to create a copy of the node that is dragged.
- cloneNodeOnDrag : false,
- // When the node is dragged and released outside its list delete it.
- dragOutsideToDelete : false
- };
-
- function Plugin(element, options)
- {
- this.w = $(document);
- this.el = $(element);
- this.options = $.extend({}, defaults, options);
- this.init();
- }
-
- Plugin.prototype = {
-
- init: function()
- {
- var list = this;
-
- list.reset();
-
- list.el.data('nestable-group', this.options.group);
-
- list.placeEl = $('
');
-
- $.each(this.el.find(list.options.itemNodeName), function(k, el) {
- list.setParent($(el));
- });
-
- list.el.on('click', 'button', function(e)
- {
- if (list.dragEl || (!hasTouch && e.button !== 0)) {
- return;
- }
- var target = $(e.currentTarget),
- action = target.data('action'),
- item = target.parent(list.options.itemNodeName);
- if (action === 'collapse') {
- list.collapseItem(item);
- }
- if (action === 'expand') {
- list.expandItem(item);
- }
- });
-
- var onStartEvent = function(e)
- {
- var handle = $(e.target);
-
- list.nestableCopy = handle.closest('.'+list.options.rootClass).clone(true);
-
- if (!handle.hasClass(list.options.handleClass)) {
- if (handle.closest('.' + list.options.noDragClass).length) {
- return;
- }
- handle = handle.closest('.' + list.options.handleClass);
- }
- if (!handle.length || list.dragEl || (!hasTouch && e.which !== 1) || (hasTouch && e.touches.length !== 1)) {
- return;
- }
- e.preventDefault();
- list.dragStart(hasTouch ? e.touches[0] : e);
- };
-
- var onMoveEvent = function(e)
- {
- if (list.dragEl) {
- e.preventDefault();
- list.dragMove(hasTouch ? e.touches[0] : e);
- }
- };
-
- var onEndEvent = function(e)
- {
- if (list.dragEl) {
- e.preventDefault();
- list.dragStop(hasTouch ? e.touches[0] : e);
- }
- };
-
- if (hasTouch) {
- list.el[0].addEventListener(eStart, onStartEvent, false);
- window.addEventListener(eMove, onMoveEvent, false);
- window.addEventListener(eEnd, onEndEvent, false);
- window.addEventListener(eCancel, onEndEvent, false);
- } else {
- list.el.on(eStart, onStartEvent);
- list.w.on(eMove, onMoveEvent);
- list.w.on(eEnd, onEndEvent);
- }
-
- var destroyNestable = function()
- {
- if (hasTouch) {
- list.el[0].removeEventListener(eStart, onStartEvent, false);
- window.removeEventListener(eMove, onMoveEvent, false);
- window.removeEventListener(eEnd, onEndEvent, false);
- window.removeEventListener(eCancel, onEndEvent, false);
- } else {
- list.el.off(eStart, onStartEvent);
- list.w.off(eMove, onMoveEvent);
- list.w.off(eEnd, onEndEvent);
- }
-
- list.el.off('click');
- list.el.unbind('destroy-nestable');
-
- list.el.data("nestable", null);
-
- var buttons = list.el[0].getElementsByTagName('button');
-
- $(buttons).remove();
- };
-
- list.el.bind('destroy-nestable', destroyNestable);
- },
-
- destroy: function ()
- {
- this.expandAll();
- this.el.trigger('destroy-nestable');
- },
-
- serialize: function()
- {
- var data,
- list = this;
- const step = function(level, depth)
- {
- var array = [ ],
- items = level.children(list.options.itemNodeName);
- items.each(function()
- {
- var li = $(this),
- item = $.extend({}, li.data()),
- sub = li.children(list.options.listNodeName);
- if (sub.length) {
- item.children = step(sub);
- }
- array.push(item);
- });
- return array;
- };
- var el;
-
- if (list.el.is(list.options.listNodeName)) {
- el = list.el;
- } else {
- el = list.el.find(list.options.listNodeName).first();
- }
- data = step(el);
- return data;
- },
-
- reset: function()
- {
- this.mouse = {
- offsetX : 0,
- offsetY : 0,
- startX : 0,
- startY : 0,
- lastX : 0,
- lastY : 0,
- nowX : 0,
- nowY : 0,
- distX : 0,
- distY : 0,
- dirAx : 0,
- dirX : 0,
- dirY : 0,
- lastDirX : 0,
- lastDirY : 0,
- distAxX : 0,
- distAxY : 0
- };
- this.moving = false;
- this.dragEl = null;
- this.dragRootEl = null;
- this.dragDepth = 0;
- this.dragItem = null;
- this.hasNewRoot = false;
- this.pointEl = null;
- this.sourceRoot = null;
- this.isOutsideRoot = false;
- },
-
- expandItem: function(li)
- {
- li.removeClass(this.options.collapsedClass);
- li.children('[data-action="expand"]').hide();
- li.children('[data-action="collapse"]').show();
- li.children(this.options.listNodeName).show();
- this.el.trigger('expand', [li]);
- li.trigger('expand');
- },
-
- collapseItem: function(li)
- {
- var lists = li.children(this.options.listNodeName);
- if (lists.length) {
- li.addClass(this.options.collapsedClass);
- li.children('[data-action="collapse"]').hide();
- li.children('[data-action="expand"]').show();
- li.children(this.options.listNodeName).hide();
- }
- this.el.trigger('collapse', [li]);
- li.trigger('collapse');
- },
-
- expandAll: function()
- {
- var list = this;
- list.el.find(list.options.itemNodeName).each(function() {
- list.expandItem($(this));
- });
- },
-
- collapseAll: function()
- {
- var list = this;
- list.el.find(list.options.itemNodeName).each(function() {
- list.collapseItem($(this));
- });
- },
-
- setParent: function(li)
- {
- if (li.children(this.options.listNodeName).length) {
- li.prepend($(this.options.expandBtnHTML));
- li.prepend($(this.options.collapseBtnHTML));
- }
- if( (' ' + li[0].className + ' ').indexOf(' ' + defaults.collapsedClass + ' ') > -1 )
- {
- li.children('[data-action="collapse"]').hide();
- } else {
- li.children('[data-action="expand"]').hide();
- }
- },
-
- unsetParent: function(li)
- {
- li.removeClass(this.options.collapsedClass);
- li.children('[data-action]').remove();
- li.children(this.options.listNodeName).remove();
- },
-
- dragStart: function(e)
- {
- var mouse = this.mouse,
- target = $(e.target),
- dragItem = target.closest('.' + this.options.handleClass).closest(this.options.itemNodeName);
-
- this.sourceRoot = target.closest('.' + this.options.rootClass);
-
- this.dragItem = dragItem;
-
- this.placeEl.css('height', dragItem.height());
-
- mouse.offsetX = e.offsetX !== undefined$1 ? e.offsetX : e.pageX - target.offset().left;
- mouse.offsetY = e.offsetY !== undefined$1 ? e.offsetY : e.pageY - target.offset().top;
- mouse.startX = mouse.lastX = e.pageX;
- mouse.startY = mouse.lastY = e.pageY;
-
- this.dragRootEl = this.el;
-
- this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
- this.dragEl.css('width', dragItem.width());
-
- // fix for zepto.js
- //dragItem.after(this.placeEl).detach().appendTo(this.dragEl);
- if(this.options.cloneNodeOnDrag) {
- dragItem.after(dragItem.clone());
- } else {
- dragItem.after(this.placeEl);
- }
- dragItem[0].parentNode.removeChild(dragItem[0]);
- dragItem.appendTo(this.dragEl);
-
- $(document.body).append(this.dragEl);
- this.dragEl.css({
- 'left' : e.pageX - mouse.offsetX,
- 'top' : e.pageY - mouse.offsetY
- });
- // total depth of dragging item
- var i, depth,
- items = this.dragEl.find(this.options.itemNodeName);
- for (i = 0; i < items.length; i++) {
- depth = $(items[i]).parents(this.options.listNodeName).length;
- if (depth > this.dragDepth) {
- this.dragDepth = depth;
- }
- }
- },
-
- dragStop: function(e)
- {
- // fix for zepto.js
- //this.placeEl.replaceWith(this.dragEl.children(this.options.itemNodeName + ':first').detach());
- var el = this.dragEl.children(this.options.itemNodeName).first();
- el[0].parentNode.removeChild(el[0]);
-
- if(this.isOutsideRoot && this.options.dragOutsideToDelete)
- {
- var parent = this.placeEl.parent();
- this.placeEl.remove();
- if (!parent.children().length) {
- this.unsetParent(parent.parent());
- }
- // If all nodes where deleted, create a placeholder element.
- if (!this.dragRootEl.find(this.options.itemNodeName).length)
- {
- this.dragRootEl.append('');
- }
- }
- else
- {
- this.placeEl.replaceWith(el);
- }
-
- if (!this.moving)
- {
- $(this.dragItem).trigger('click');
- }
-
- var i;
- var isRejected = false;
- for (i = 0; i < this.options.reject.length; i++)
- {
- var reject = this.options.reject[i];
- if (reject.rule.apply(this.dragRootEl))
- {
- var nestableDragEl = el.clone(true);
- this.dragRootEl.html(this.nestableCopy.children().clone(true));
- if (reject.action) {
- reject.action.apply(this.dragRootEl, [nestableDragEl]);
- }
-
- isRejected = true;
- break;
- }
- }
-
- if (!isRejected)
- {
- this.dragEl.remove();
- this.el.trigger('change');
-
- //Let's find out new parent id
- var parentItem = el.parent().parent();
- var parentId = null;
- if(parentItem !== null && !parentItem.is('.' + this.options.rootClass))
- parentId = parentItem.data('id');
-
- if($.isFunction(this.options.dropCallback))
- {
- var details = {
- sourceId : el.data('id'),
- destId : parentId,
- sourceEl : el,
- destParent : parentItem,
- destRoot : el.closest('.' + this.options.rootClass),
- sourceRoot : this.sourceRoot
- };
- this.options.dropCallback.call(this, details);
- }
-
- if (this.hasNewRoot) {
- this.dragRootEl.trigger('change');
- }
-
- this.reset();
- }
- },
-
- dragMove: function(e)
- {
- var list, parent, prev, next, depth,
- opt = this.options,
- mouse = this.mouse;
-
- this.dragEl.css({
- 'left' : e.pageX - mouse.offsetX,
- 'top' : e.pageY - mouse.offsetY
- });
-
- // mouse position last events
- mouse.lastX = mouse.nowX;
- mouse.lastY = mouse.nowY;
- // mouse position this events
- mouse.nowX = e.pageX;
- mouse.nowY = e.pageY;
- // distance mouse moved between events
- mouse.distX = mouse.nowX - mouse.lastX;
- mouse.distY = mouse.nowY - mouse.lastY;
- // direction mouse was moving
- mouse.lastDirX = mouse.dirX;
- mouse.lastDirY = mouse.dirY;
- // direction mouse is now moving (on both axis)
- mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
- mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
- // axis mouse is now moving on
- var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
-
- // do nothing on first move
- if (!this.moving) {
- mouse.dirAx = newAx;
- this.moving = true;
- return;
- }
-
- // calc distance moved on this axis (and direction)
- if (mouse.dirAx !== newAx) {
- mouse.distAxX = 0;
- mouse.distAxY = 0;
- } else {
- mouse.distAxX += Math.abs(mouse.distX);
- if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
- mouse.distAxX = 0;
- }
- mouse.distAxY += Math.abs(mouse.distY);
- if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
- mouse.distAxY = 0;
- }
- }
- mouse.dirAx = newAx;
-
- /**
- * move horizontal
- */
- if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
- // reset move distance on x-axis for new phase
- mouse.distAxX = 0;
- prev = this.placeEl.prev(opt.itemNodeName);
- // increase horizontal level if previous sibling exists and is not collapsed
- if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass) && !prev.hasClass(opt.noChildrenClass)) {
- // cannot increase level when item above is collapsed
- list = prev.find(opt.listNodeName).last();
- // check if depth limit has reached
- depth = this.placeEl.parents(opt.listNodeName).length;
- if (depth + this.dragDepth <= opt.maxDepth) {
- // create new sub-level if one doesn't exist
- if (!list.length) {
- list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
- list.append(this.placeEl);
- prev.append(list);
- this.setParent(prev);
- } else {
- // else append to next level up
- list = prev.children(opt.listNodeName).last();
- list.append(this.placeEl);
- }
- }
- }
- // decrease horizontal level
- if (mouse.distX < 0) {
- // we can't decrease a level if an item preceeds the current one
- next = this.placeEl.next(opt.itemNodeName);
- if (!next.length) {
- parent = this.placeEl.parent();
- this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
- if (!parent.children().length) {
- this.unsetParent(parent.parent());
- }
- }
- }
- }
-
- var isEmpty = false;
-
- // find list item under cursor
- if (!hasPointerEvents) {
- this.dragEl[0].style.visibility = 'hidden';
- }
-
- this.pointEl = $(document.elementFromPoint(e.pageX - document.documentElement.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
-
- // Check if the node is dragged outside of its list.
- if(this.dragRootEl.has(this.pointEl).length) {
- this.isOutsideRoot = false;
- this.dragEl[0].style.opacity = 1;
- } else {
- this.isOutsideRoot = true;
- this.dragEl[0].style.opacity = 0.5;
- }
-
- // find parent list of item under cursor
- var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
- isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
-
- this.isOutsideRoot = !pointElRoot.length;
-
- if (!hasPointerEvents) {
- this.dragEl[0].style.visibility = 'visible';
- }
- if (this.pointEl.hasClass(opt.handleClass)) {
- this.pointEl = this.pointEl.closest( opt.itemNodeName );
- }
-
- if (opt.maxDepth == 1 && !this.pointEl.hasClass(opt.itemClass)) {
- this.pointEl = this.pointEl.closest("." + opt.itemClass);
- }
-
- if (this.pointEl.hasClass(opt.emptyClass)) {
- isEmpty = true;
- }
- else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
- return;
- }
-
- /**
- * move vertical
- */
- if (!mouse.dirAx || isNewRoot || isEmpty) {
- // check if groups match if dragging over new root
- if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
- return;
- }
- // check depth limit
- depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
- if (depth > opt.maxDepth) {
- return;
- }
- var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
- parent = this.placeEl.parent();
- // if empty create new list to replace empty placeholder
- if (isEmpty) {
- list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
- list.append(this.placeEl);
- this.pointEl.replaceWith(list);
- }
- else if (before) {
- this.pointEl.before(this.placeEl);
- }
- else {
- this.pointEl.after(this.placeEl);
- }
- if (!parent.children().length) {
- this.unsetParent(parent.parent());
- }
- if (!this.dragRootEl.find(opt.itemNodeName).length) {
- this.dragRootEl.append('');
- }
- // parent root list has changed
- this.dragRootEl = pointElRoot;
- if (isNewRoot) {
- this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
- }
- }
- }
-
- };
-
- $.fn.nestable = function(params)
- {
- var lists = this,
- retval = this;
-
- var generateUid = function (separator) {
- var delim = "-";
-
- function S4() {
- return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
- }
-
- return (S4() + S4() + delim + S4() + delim + S4() + delim + S4() + delim + S4() + S4() + S4());
- };
-
- lists.each(function()
- {
- var plugin = $(this).data("nestable");
-
- if (!plugin) {
- $(this).data("nestable", new Plugin(this, params));
- $(this).data("nestable-id", generateUid());
- } else {
- if (typeof params === 'string' && typeof plugin[params] === 'function') {
- retval = plugin[params]();
- }
- }
- });
-
- return retval || lists;
- };
-
-})(window.jQuery || window.Zepto, window, document);
-
-/* From https://github.com/TimSchlechter/bootstrap-tagsinput/blob/2661784c2c281d3a69b93897ff3f39e4ffa5cbd1/dist/bootstrap-tagsinput.js */
-
-/* The MIT License (MIT)
-
-Copyright (c) 2013 Tim Schlechter
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/* Retrieved 12 February 2014 */
-
-(function ($) {
-
- var defaultOptions = {
- tagClass: function(item) {
- return 'badge badge-info bg-info';
- },
- itemValue: function(item) {
- return item ? item.toString() : item;
- },
- itemText: function(item) {
- return this.itemValue(item);
- },
- freeInput: true,
- maxTags: undefined,
- confirmKeys: [13],
- onTagExists: function(item, $tag) {
- $tag.hide().fadeIn();
- }
- };
-
- /**
- * Constructor function
- */
- function TagsInput(element, options) {
- this.itemsArray = [];
-
- this.$element = $(element);
- this.$element.hide();
-
- this.isSelect = (element.tagName === 'SELECT');
- this.multiple = (this.isSelect && element.hasAttribute('multiple'));
- this.objectItems = options && options.itemValue;
- this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
- this.inputSize = Math.max(1, this.placeholderText.length);
-
- this.$container = $('');
- this.$input = $('').appendTo(this.$container);
-
- this.$element.after(this.$container);
-
- this.build(options);
- }
-
- TagsInput.prototype = {
- constructor: TagsInput,
-
- /**
- * Adds the given item as a new tag. Pass true to dontPushVal to prevent
- * updating the elements val()
- */
- add: function(item, dontPushVal) {
- var self = this;
-
- if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
- return;
-
- // Ignore falsey values, except false
- if (item !== false && !item)
- return;
-
- // Throw an error when trying to add an object while the itemValue option was not set
- if (typeof item === "object" && !self.objectItems)
- throw("Can't add objects when itemValue option is not set");
-
- // Ignore strings only containg whitespace
- if (item.toString().match(/^\s*$/))
- return;
-
- // If SELECT but not multiple, remove current tag
- if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
- self.remove(self.itemsArray[0]);
-
- if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
- var items = item.split(',');
- if (items.length > 1) {
- for (var i = 0; i < items.length; i++) {
- this.add(items[i], true);
- }
-
- if (!dontPushVal)
- self.pushVal();
- return;
- }
- }
-
- var itemValue = self.options.itemValue(item),
- itemText = self.options.itemText(item),
- tagClass = self.options.tagClass(item);
-
- // Ignore items allready added
- var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
- if (existing) {
- // Invoke onTagExists
- if (self.options.onTagExists) {
- var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
- self.options.onTagExists(item, $existingTag);
- }
- return;
- }
-
- // register item in internal array and map
- self.itemsArray.push(item);
-
- // add a tag element
- var $tag = $('' + htmlEncode(itemText) + '');
- $tag.data('item', item);
- self.findInputWrapper().before($tag);
- $tag.after(' ');
-
- // add if item represents a value not present in one of the 's options
- if (self.isSelect && !$('option[value="' + escape(itemValue) + '"]',self.$element)[0]) {
- var $option = $('');
- $option.data('item', item);
- $option.attr('value', itemValue);
- self.$element.append($option);
- }
-
- if (!dontPushVal)
- self.pushVal();
-
- // Add class when reached maxTags
- if (self.options.maxTags === self.itemsArray.length)
- self.$container.addClass('bootstrap-tagsinput-max');
-
- self.$element.trigger($.Event('itemAdded', { item: item }));
- },
-
- /**
- * Removes the given item. Pass true to dontPushVal to prevent updating the
- * elements val()
- */
- remove: function(item, dontPushVal) {
- var self = this;
-
- if (self.objectItems) {
- if (typeof item === "object")
- item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } )[0];
- else
- item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } )[0];
- }
-
- if (item) {
- $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
- $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
- self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
- }
-
- if (!dontPushVal)
- self.pushVal();
-
- // Remove class when reached maxTags
- if (self.options.maxTags > self.itemsArray.length)
- self.$container.removeClass('bootstrap-tagsinput-max');
-
- self.$element.trigger($.Event('itemRemoved', { item: item }));
- },
-
- /**
- * Removes all items
- */
- removeAll: function() {
- var self = this;
-
- $('.tag', self.$container).remove();
- $('option', self.$element).remove();
-
- while(self.itemsArray.length > 0)
- self.itemsArray.pop();
-
- self.pushVal();
-
- if (self.options.maxTags && !this.isEnabled())
- this.enable();
- },
-
- /**
- * Refreshes the tags so they match the text/value of their corresponding
- * item.
- */
- refresh: function() {
- var self = this;
- $('.tag', self.$container).each(function() {
- var $tag = $(this),
- item = $tag.data('item'),
- itemValue = self.options.itemValue(item),
- itemText = self.options.itemText(item),
- tagClass = self.options.tagClass(item);
-
- // Update tag's class and inner text
- $tag.attr('class', null);
- $tag.addClass('tag ' + htmlEncode(tagClass));
- $tag.contents().filter(function() {
- return this.nodeType == 3;
- })[0].nodeValue = htmlEncode(itemText);
-
- if (self.isSelect) {
- var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
- option.attr('value', itemValue);
- }
- });
- },
-
- /**
- * Returns the items added as tags
- */
- items: function() {
- return this.itemsArray;
- },
-
- /**
- * Assembly value by retrieving the value of each item, and set it on the
- * element.
- */
- pushVal: function() {
- var self = this,
- val = $.map(self.items(), function(item) {
- return self.options.itemValue(item).toString();
- });
-
- self.$element.val(val, true).trigger('change');
- },
-
- /**
- * Initializes the tags input behaviour on the element
- */
- build: function(options) {
- var self = this;
-
- self.options = $.extend({}, defaultOptions, options);
- var typeahead = self.options.typeahead || {};
-
- // When itemValue is set, freeInput should always be false
- if (self.objectItems)
- self.options.freeInput = false;
-
- makeOptionItemFunction(self.options, 'itemValue');
- makeOptionItemFunction(self.options, 'itemText');
- makeOptionItemFunction(self.options, 'tagClass');
-
- // for backwards compatibility, self.options.source is deprecated
- if (self.options.source)
- typeahead.source = self.options.source;
-
- if (typeahead.source && $.fn.typeahead) {
- makeOptionFunction(typeahead, 'source');
-
- self.$input.typeahead({
- source: function (query, process) {
- function processItems(items) {
- var texts = [];
-
- for (var i = 0; i < items.length; i++) {
- var text = self.options.itemText(items[i]);
- map[text] = items[i];
- texts.push(text);
- }
- process(texts);
- }
-
- this.map = {};
- var map = this.map,
- data = typeahead.source(query);
-
- if ($.isFunction(data.success)) {
- // support for Angular promises
- data.success(processItems);
- } else {
- // support for functions and jquery promises
- $.when(data)
- .then(processItems);
- }
- },
- updater: function (text) {
- self.add(this.map[text]);
- },
- matcher: function (text) {
- return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
- },
- sorter: function (texts) {
- return texts.sort();
- },
- highlighter: function (text) {
- var regex = new RegExp( '(' + this.query + ')', 'gi' );
- return text.replace( regex, "$1" );
- }
- });
- }
-
- self.$container.on('click', $.proxy(function(event) {
- self.$input.focus();
- }, self));
-
- self.$container.on('keydown', 'input', $.proxy(function(event) {
- var $input = $(event.target),
- $inputWrapper = self.findInputWrapper();
-
- switch (event.which) {
- // BACKSPACE
- case 8:
- if (doGetCaretPosition($input[0]) === 0) {
- var prev = $inputWrapper.prev();
- if (prev) {
- self.remove(prev.data('item'));
- }
- }
- break;
-
- // DELETE
- case 46:
- if (doGetCaretPosition($input[0]) === 0) {
- var next = $inputWrapper.next();
- if (next) {
- self.remove(next.data('item'));
- }
- }
- break;
-
- // LEFT ARROW
- case 37:
- // Try to move the input before the previous tag
- var $prevTag = $inputWrapper.prev();
- if ($input.val().length === 0 && $prevTag[0]) {
- $prevTag.before($inputWrapper);
- $input.focus();
- }
- break;
- // RIGHT ARROW
- case 39:
- // Try to move the input after the next tag
- var $nextTag = $inputWrapper.next();
- if ($input.val().length === 0 && $nextTag[0]) {
- $nextTag.after($inputWrapper);
- $input.focus();
- }
- break;
- default:
- // When key corresponds one of the confirmKeys, add current input
- // as a new tag
- if (self.options.freeInput && $.inArray(event.which, self.options.confirmKeys) >= 0) {
- self.add($input.val());
- $input.val('');
- event.preventDefault();
- }
- }
-
- // Reset internal input's size
- $input.attr('size', Math.max(this.inputSize, $input.val().length));
- }, self));
-
- // Remove icon clicked
- self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
- self.remove($(event.target).closest('.tag').data('item'));
- }, self));
-
- // Only add existing value as tags when using strings as tags
- if (self.options.itemValue === defaultOptions.itemValue) {
- if (self.$element[0].tagName === 'INPUT') {
- self.add(self.$element.val());
- } else {
- $('option', self.$element).each(function() {
- self.add($(this).attr('value'), true);
- });
- }
- }
- },
-
- /**
- * Removes all tagsinput behaviour and unregsiter all event handlers
- */
- destroy: function() {
- var self = this;
-
- // Unbind events
- self.$container.off('keypress', 'input');
- self.$container.off('click', '[role=remove]');
-
- self.$container.remove();
- self.$element.removeData('tagsinput');
- self.$element.show();
- },
-
- /**
- * Sets focus on the tagsinput
- */
- focus: function() {
- this.$input.focus();
- },
-
- /**
- * Returns the internal input element
- */
- input: function() {
- return this.$input;
- },
-
- /**
- * Returns the element which is wrapped around the internal input. This
- * is normally the $container, but typeahead.js moves the $input element.
- */
- findInputWrapper: function() {
- var elt = this.$input[0],
- container = this.$container[0];
- while(elt && elt.parentNode !== container)
- elt = elt.parentNode;
-
- return $(elt);
- }
- };
-
- /**
- * Register JQuery plugin
- */
- $.fn.tagsinput = function(arg1, arg2) {
- var results = [];
-
- this.each(function() {
- var tagsinput = $(this).data('tagsinput');
-
- // Initialize a new tags input
- if (!tagsinput) {
- tagsinput = new TagsInput(this, arg1);
- $(this).data('tagsinput', tagsinput);
- results.push(tagsinput);
-
- if (this.tagName === 'SELECT') {
- $('option', $(this)).attr('selected', 'selected');
- }
-
- // Init tags from $(this).val()
- $(this).val($(this).val());
- } else {
- // Invoke function on existing tags input
- var retVal = tagsinput[arg1](arg2);
- if (retVal !== undefined)
- results.push(retVal);
- }
- });
-
- if ( typeof arg1 == 'string') {
- // Return the results from the invoked function calls
- return results.length > 1 ? results : results[0];
- } else {
- return results;
- }
- };
-
- $.fn.tagsinput.Constructor = TagsInput;
-
- /**
- * Most options support both a string or number as well as a function as
- * option value. This function makes sure that the option with the given
- * key in the given options is wrapped in a function
- */
- function makeOptionItemFunction(options, key) {
- if (typeof options[key] !== 'function') {
- var propertyName = options[key];
- options[key] = function(item) { return item[propertyName]; };
- }
- }
- function makeOptionFunction(options, key) {
- if (typeof options[key] !== 'function') {
- var value = options[key];
- options[key] = function() { return value; };
- }
- }
- /**
- * HtmlEncodes the given value
- */
- var htmlEncodeContainer = $('');
- function htmlEncode(value) {
- if (value) {
- return htmlEncodeContainer.text(value).html();
- } else {
- return '';
- }
- }
-
- /**
- * Returns the position of the caret in the given input field
- * http://flightschool.acylt.com/devnotes/caret-position-woes/
- */
- function doGetCaretPosition(oField) {
- var iCaretPos = 0;
- if (document.selection) {
- oField.focus ();
- var oSel = document.selection.createRange();
- oSel.moveStart ('character', -oField.value.length);
- iCaretPos = oSel.text.length;
- } else if (oField.selectionStart || oField.selectionStart == '0') {
- iCaretPos = oField.selectionStart;
- }
- return (iCaretPos);
- }
-
- /**
- * Initialize tagsinput behaviour on inputs and selects which have
- * data-role=tagsinput
- */
- $(function() {
- $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
- });
-})(window.jQuery);
-
-/*!
- * typeahead.js 0.10.2
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-!function(a){var b={isMsie:function(){return /(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return !a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return "string"==typeof a},isNumber:function(a){return "number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return "undefined"==typeof a},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d);},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return (d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return (d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0);},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i));},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d);},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},noop:function(){}},c="0.10.2",d=function(){function a(a){return a.split(/\s+/)}function b(a){return a.split(/\W+/)}function c(a){return function(b){return function(c){return a(c[b])}}}return {nonword:b,whitespace:a,obj:{nonword:c(b),whitespace:c(a)}}}(),e=function(){function a(a){this.maxSize=a||100,this.size=0,this.hash={},this.list=new c;}function c(){this.head=this.tail=null;}function d(a,b){this.key=a,this.val=b,this.prev=this.next=null;}return b.mixin(a.prototype,{set:function(a,b){var c,e=this.list.tail;this.size>=this.maxSize&&(this.list.remove(e),delete this.hash[e.key]),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new d(a,b),this.list.add(c),this.hash[a]=c,this.size++);},get:function(a){var b=this.hash[a];return b?(this.list.moveToFront(b),b.val):void 0}}),b.mixin(c.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a;},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev;},moveToFront:function(a){this.remove(a),this.add(a);}}),a}(),f=function(){function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+this.prefix);}function c(){return (new Date).getTime()}function d(a){return JSON.stringify(b.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~");}catch(h){f=null;}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return b.isNumber(g)?f.setItem(this._ttlKey(a),d(c()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return b.isNumber(d)&&c()>d?!0:!1}}:{get:b.noop,set:b.noop,remove:b.noop,clear:b.noop,isExpired:b.noop},b.mixin(a.prototype,g),a}(),g=function(){function c(b){b=b||{},this._send=b.transport?d(b.transport):a.ajax,this._get=b.rateLimiter?b.rateLimiter(this._get):this._get;}function d(c){return function(d,e){function f(a){b.defer(function(){h.resolve(a);});}function g(a){b.defer(function(){h.reject(a);});}var h=a.Deferred();return c(d,e,f,g),h}}var f=0,g={},h=6,i=new e(10);return c.setMaxPendingRequests=function(a){h=a;},c.resetCache=function(){i=new e(10);},b.mixin(c.prototype,{_get:function(a,b,c){function d(b){c&&c(null,b),i.set(a,b);}function e(){c&&c(!0);}function j(){f--,delete g[a],l.onDeckRequestArgs&&(l._get.apply(l,l.onDeckRequestArgs),l.onDeckRequestArgs=null);}var k,l=this;(k=g[a])?k.done(d).fail(e):h>f?(f++,g[a]=this._send(a,b).done(d).fail(e).always(j)):this.onDeckRequestArgs=[].slice.call(arguments,0);},get:function(a,c,d){var e;return b.isFunction(c)&&(d=c,c={}),(e=i.get(a))?b.defer(function(){d&&d(null,e);}):this._get(a,c,d),!!e}}),c}(),h=function(){function c(b){b=b||{},b.datumTokenizer&&b.queryTokenizer||a.error("datumTokenizer and queryTokenizer are both required"),this.datumTokenizer=b.datumTokenizer,this.queryTokenizer=b.queryTokenizer,this.reset();}function d(a){return a=b.filter(a,function(a){return !!a}),a=b.map(a,function(a){return a.toLowerCase()})}function e(){return {ids:[],children:{}}}function f(a){for(var b={},c=[],d=0;db[e]?e++:(f.push(a[d]),d++,e++);return f}return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie;},add:function(a){var c=this;a=b.isArray(a)?a:[a],b.each(a,function(a){var f,g;f=c.datums.push(a)-1,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b.children[g]||(b.children[g]=e()),b.ids.push(f);});});},get:function(a){var c,e,h=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length)return !1;for(b=h.trie,c=a.split("");b&&(d=c.shift());)b=b.children[d];return b&&0===c.length?(f=b.ids.slice(0),void(e=e?g(e,f):f)):(e=[],!1)}),e?b.map(f(e),function(a){return h.datums[a]}):[]},reset:function(){this.datums=[],this.trie=e();},serialize:function(){return {datums:this.datums,trie:this.trie}}}),c}(),i=function(){function d(a){return a.local||null}function e(d){var e,f;return f={url:null,thumbprint:"",ttl:864e5,filter:null,ajax:{}},(e=d.prefetch||null)&&(e=b.isString(e)?{url:e}:e,e=b.mixin(f,e),e.thumbprint=c+e.thumbprint,e.ajax.type=e.ajax.type||"GET",e.ajax.dataType=e.ajax.dataType||"json",!e.url&&a.error("prefetch requires url to be set")),e}function f(c){function d(a){return function(c){return b.debounce(c,a)}}function e(a){return function(c){return b.throttle(c,a)}}var f,g;return g={url:null,wildcard:"%QUERY",replace:null,rateLimitBy:"debounce",rateLimitWait:300,send:null,filter:null,ajax:{}},(f=c.remote||null)&&(f=b.isString(f)?{url:f}:f,f=b.mixin(g,f),f.rateLimiter=/^throttle$/i.test(f.rateLimitBy)?e(f.rateLimitWait):d(f.rateLimitWait),f.ajax.type=f.ajax.type||"GET",f.ajax.dataType=f.ajax.dataType||"json",delete f.rateLimitBy,delete f.rateLimitWait,!f.url&&a.error("remote requires url to be set")),f}return {local:d,prefetch:e,remote:f}}();!function(c){function e(b){b&&(b.local||b.prefetch||b.remote)||a.error("one of local, prefetch, or remote is required"),this.limit=b.limit||5,this.sorter=j(b.sorter),this.dupDetector=b.dupDetector||k,this.local=i.local(b),this.prefetch=i.prefetch(b),this.remote=i.remote(b),this.cacheKey=this.prefetch?this.prefetch.cacheKey||this.prefetch.url:null,this.index=new h({datumTokenizer:b.datumTokenizer,queryTokenizer:b.queryTokenizer}),this.storage=this.cacheKey?new f(this.cacheKey):null;}function j(a){function c(b){return b.sort(a)}function d(a){return a}return b.isFunction(a)?c:d}function k(){return !1}var l,m;return l=c.Bloodhound,m={data:"data",protocol:"protocol",thumbprint:"thumbprint"},c.Bloodhound=e,e.noConflict=function(){return c.Bloodhound=l,e},e.tokenizers=d,b.mixin(e.prototype,{_loadPrefetch:function(b){function c(a){f.clear(),f.add(b.filter?b.filter(a):a),f._saveToStorage(f.index.serialize(),b.thumbprint,b.ttl);}var d,e,f=this;return (d=this._readFromStorage(b.thumbprint))?(this.index.bootstrap(d),e=a.Deferred().resolve()):e=a.ajax(b.url,b.ajax).done(c),e},_getFromRemote:function(a,b){function c(a,c){b(a?[]:f.remote.filter?f.remote.filter(c):c);}var d,e,f=this;return a=a||"",e=encodeURIComponent(a),d=this.remote.replace?this.remote.replace(this.remote.url,a):this.remote.url.replace(this.remote.wildcard,e),this.transport.get(d,this.remote.ajax,c)},_saveToStorage:function(a,b,c){this.storage&&(this.storage.set(m.data,a,c),this.storage.set(m.protocol,location.protocol,c),this.storage.set(m.thumbprint,b,c));},_readFromStorage:function(a){var b,c={};return this.storage&&(c.data=this.storage.get(m.data),c.protocol=this.storage.get(m.protocol),c.thumbprint=this.storage.get(m.thumbprint)),b=c.thumbprint!==a||c.protocol!==location.protocol,c.data&&!b?c.data:null},_initialize:function(){function c(){e.add(b.isFunction(f)?f():f);}var d,e=this,f=this.local;return d=this.prefetch?this._loadPrefetch(this.prefetch):a.Deferred().resolve(),f&&d.done(c),this.transport=this.remote?new g(this.remote):null,this.initPromise=d.promise()},initialize:function(a){return !this.initPromise||a?this._initialize():this.initPromise},add:function(a){this.index.add(a);},get:function(a,c){function d(a){var d=f.slice(0);b.each(a,function(a){var c;return c=b.some(d,function(b){return e.dupDetector(a,b)}),!c&&d.push(a),d.length0||!this.transport)&&c&&c(f);},clear:function(){this.index.reset();},clearPrefetchCache:function(){this.storage&&this.storage.clear();},clearRemoteCache:function(){this.transport&&g.resetCache();},ttAdapter:function(){return b.bind(this.get,this)}}),e}(this);var j={wrapper:'',dropdown:'',dataset:'',suggestions:'',suggestion:''},k={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};b.isMsie()&&b.mixin(k.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),b.isMsie()&&b.isMsie()<=7&&b.mixin(k.input,{marginTop:"-1px"});var l=function(){function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el);}var d="typeahead:";return b.mixin(c.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b);}}),c}(),m=function(){function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0;!d&&e').css({position:"absolute",visibility:"hidden",whiteSpace:"pre",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function e(a,b){return c.normalizeQuery(a)===c.normalizeQuery(b)}function f(a){return a.altKey||a.ctrlKey||a.metaKey||a.shiftKey}var g;return g={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},c.normalizeQuery=function(a){return (a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},b.mixin(c.prototype,m,{_onBlur:function(){this.resetInputValue(),this.trigger("blurred");},_onFocus:function(){this.trigger("focused");},_onKeydown:function(a){var b=g[a.which||a.keyCode];this._managePreventDefault(b,a),b&&this._shouldTrigger(b,a)&&this.trigger(b+"Keyed",a);},_onInput:function(){this._checkInputValue();},_managePreventDefault:function(a,b){var c,d,e;switch(a){case"tab":d=this.getHint(),e=this.getInputValue(),c=d&&d!==e&&!f(b);break;case"up":case"down":c=!f(b);break;default:c=!1;}c&&b.preventDefault();},_shouldTrigger:function(a,b){var c;switch(a){case"tab":c=!f(b);break;default:c=!0;}return c},_checkInputValue:function(){var a,b,c;a=this.getInputValue(),b=e(a,this.query),c=b?this.query.length!==a.length:!1,b?c&&this.trigger("whitespaceChanged",this.query):this.trigger("queryChanged",this.query=a);},focus:function(){this.$input.focus();},blur:function(){this.$input.blur();},getQuery:function(){return this.query},setQuery:function(a){this.query=a;},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),b?this.clearHint():this._checkInputValue();},resetInputValue:function(){this.setInputValue(this.query,!0);},getHint:function(){return this.$hint.val()},setHint:function(a){this.$hint.val(a);},clearHint:function(){this.setHint("");},clearHintIfInvalid:function(){var a,b,c,d;a=this.getInputValue(),b=this.getHint(),c=a!==b&&0===b.indexOf(a),d=""!==a&&c&&!this.hasOverflow(),!d&&this.clearHint();},getLanguageDirection:function(){return (this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var a=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=a},isCursorAtEnd:function(){var a,c,d;return a=this.$input.val().length,c=this.$input[0].selectionStart,b.isNumber(c)?c===a:document.selection?(d=document.selection.createRange(),d.moveStart("character",-a),a===d.text.length):!0},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null;}}),c}(),p=function(){function c(c){c=c||{},c.templates=c.templates||{},c.source||a.error("missing source"),c.name&&!f(c.name)&&a.error("invalid dataset name: "+c.name),this.query=null,this.highlight=!!c.highlight,this.name=c.name||b.getUniqueId(),this.source=c.source,this.displayFn=d(c.display||c.displayKey),this.templates=e(c.templates,this.displayFn),this.$el=a(j.dataset.replace("%CLASS%",this.name));}function d(a){function c(b){return b[a]}return a=a||"value",b.isFunction(a)?a:c}function e(a,c){function d(a){return ""+c(a)+"
"}return {empty:a.empty&&b.templatify(a.empty),header:a.header&&b.templatify(a.header),footer:a.footer&&b.templatify(a.footer),suggestion:a.suggestion||d}}function f(a){return /^[_a-zA-Z0-9-]+$/.test(a)}var g="ttDataset",h="ttValue",i="ttDatum";return c.extractDatasetName=function(b){return a(b).data(g)},c.extractValue=function(b){return a(b).data(h)},c.extractDatum=function(b){return a(b).data(i)},b.mixin(c.prototype,m,{_render:function(c,d){function e(){return p.templates.empty({query:c,isEmpty:!0})}function f(){function e(b){var c;return c=a(j.suggestion).append(p.templates.suggestion(b)).data(g,p.name).data(h,p.displayFn(b)).data(i,b),c.children().each(function(){a(this).css(k.suggestionChild);}),c}var f,l;return f=a(j.suggestions).css(k.suggestions),l=b.map(d,e),f.append.apply(f,l),p.highlight&&n({node:f[0],pattern:c}),f}function l(){return p.templates.header({query:c,isEmpty:!o})}function m(){return p.templates.footer({query:c,isEmpty:!o})}if(this.$el){var o,p=this;this.$el.empty(),o=d&&d.length,!o&&this.templates.empty?this.$el.html(e()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null):o&&this.$el.html(f()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null),this.trigger("rendered");}},getRoot:function(){return this.$el},update:function(a){function b(b){c.canceled||a!==c.query||c._render(a,b);}var c=this;this.query=a,this.canceled=!1,this.source(a,b);},cancel:function(){this.canceled=!0;},clear:function(){this.cancel(),this.$el.empty(),this.trigger("rendered");},isEmpty:function(){return this.$el.is(":empty")},destroy:function(){this.$el=null;}}),c}(),q=function(){function c(c){var e,f,g,h=this;c=c||{},c.menu||a.error("menu is required"),this.isOpen=!1,this.isEmpty=!0,this.datasets=b.map(c.datasets,d),e=b.bind(this._onSuggestionClick,this),f=b.bind(this._onSuggestionMouseEnter,this),g=b.bind(this._onSuggestionMouseLeave,this),this.$menu=a(c.menu).on("click.tt",".tt-suggestion",e).on("mouseenter.tt",".tt-suggestion",f).on("mouseleave.tt",".tt-suggestion",g),b.each(this.datasets,function(a){h.$menu.append(a.getRoot()),a.onSync("rendered",h._onRendered,h);});}function d(a){return new p(a)}return b.mixin(c.prototype,m,{_onSuggestionClick:function(b){this.trigger("suggestionClicked",a(b.currentTarget));},_onSuggestionMouseEnter:function(b){this._removeCursor(),this._setCursor(a(b.currentTarget),!0);},_onSuggestionMouseLeave:function(){this._removeCursor();},_onRendered:function(){function a(a){return a.isEmpty()}this.isEmpty=b.every(this.datasets,a),this.isEmpty?this._hide():this.isOpen&&this._show(),this.trigger("datasetRendered");},_hide:function(){this.$menu.hide();},_show:function(){this.$menu.css("display","block");},_getSuggestions:function(){return this.$menu.find(".tt-suggestion")},_getCursor:function(){return this.$menu.find(".tt-cursor").first()},_setCursor:function(a,b){a.first().addClass("tt-cursor"),!b&&this.trigger("cursorMoved");},_removeCursor:function(){this._getCursor().removeClass("tt-cursor");},_moveCursor:function(a){var b,c,d,e;if(this.isOpen){if(c=this._getCursor(),b=this._getSuggestions(),this._removeCursor(),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return void this.trigger("cursorRemoved");-1>d&&(d=b.length-1),this._setCursor(e=b.eq(d)),this._ensureVisible(e);}},_ensureVisible:function(a){var b,c,d,e;b=a.position().top,c=b+a.outerHeight(!0),d=this.$menu.scrollTop(),e=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),0>b?this.$menu.scrollTop(d+b):c>e&&this.$menu.scrollTop(d+(c-e));},close:function(){this.isOpen&&(this.isOpen=!1,this._removeCursor(),this._hide(),this.trigger("closed"));},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"));},setLanguageDirection:function(a){this.$menu.css("ltr"===a?k.ltr:k.rtl);},moveCursorUp:function(){this._moveCursor(-1);},moveCursorDown:function(){this._moveCursor(1);},getDatumForSuggestion:function(a){var b=null;return a.length&&(b={raw:p.extractDatum(a),value:p.extractValue(a),datasetName:p.extractDatasetName(a)}),b},getDatumForCursor:function(){return this.getDatumForSuggestion(this._getCursor().first())},getDatumForTopSuggestion:function(){return this.getDatumForSuggestion(this._getSuggestions().first())},update:function(a){function c(b){b.update(a);}b.each(this.datasets,c);},empty:function(){function a(a){a.clear();}b.each(this.datasets,a),this.isEmpty=!0;},isVisible:function(){return this.isOpen&&!this.isEmpty},destroy:function(){function a(a){a.destroy();}this.$menu.off(".tt"),this.$menu=null,b.each(this.datasets,a);}}),c}(),r=function(){function c(c){var e,f,g;c=c||{},c.input||a.error("missing input"),this.isActivated=!1,this.autoselect=!!c.autoselect,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.$node=d(c.input,c.withHint),e=this.$node.find(".tt-dropdown-menu"),f=this.$node.find(".tt-input"),g=this.$node.find(".tt-hint"),f.on("blur.tt",function(a){var c,d,g;c=document.activeElement,d=e.is(c),g=e.has(c).length>0,b.isMsie()&&(d||g)&&(a.preventDefault(),a.stopImmediatePropagation(),b.defer(function(){f.focus();}));}),e.on("mousedown.tt",function(a){a.preventDefault();}),this.eventBus=c.eventBus||new l({el:f}),this.dropdown=new q({menu:e,datasets:c.datasets}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new o({input:f,hint:g}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),this._setLanguageDirection();}function d(b,c){var d,f,h,i;d=a(b),f=a(j.wrapper).css(k.wrapper),h=a(j.dropdown).css(k.dropdown),i=d.clone().css(k.hint).css(e(d)),i.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled",!0).attr({autocomplete:"off",spellcheck:"false"}),d.data(g,{dir:d.attr("dir"),autocomplete:d.attr("autocomplete"),spellcheck:d.attr("spellcheck"),style:d.attr("style")}),d.addClass("tt-input").attr({autocomplete:"off",spellcheck:!1}).css(c?k.input:k.inputWithNoHint);try{!d.attr("dir")&&d.attr("dir","auto");}catch(l){}return d.wrap(f).parent().prepend(c?i:null).append(h)}function e(a){return {backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function f(a){var c=a.find(".tt-input");b.each(c.data(g),function(a,d){b.isUndefined(a)?c.removeAttr(d):c.attr(d,a);}),c.detach().removeData(g).removeClass("tt-input").insertAfter(a),a.remove();}var g="ttAttrs";return b.mixin(c.prototype,{_onSuggestionClicked:function(a,b){var c;(c=this.dropdown.getDatumForSuggestion(b))&&this._select(c);},_onCursorMoved:function(){var a=this.dropdown.getDatumForCursor();this.input.setInputValue(a.value,!0),this.eventBus.trigger("cursorchanged",a.raw,a.datasetName);},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint();},_onDatasetRendered:function(){this._updateHint();},_onOpened:function(){this._updateHint(),this.eventBus.trigger("opened");},_onClosed:function(){this.input.clearHint(),this.eventBus.trigger("closed");},_onFocused:function(){this.isActivated=!0,this.dropdown.open();},_onBlurred:function(){this.isActivated=!1,this.dropdown.empty(),this.dropdown.close();},_onEnterKeyed:function(a,b){var c,d;c=this.dropdown.getDatumForCursor(),d=this.dropdown.getDatumForTopSuggestion(),c?(this._select(c),b.preventDefault()):this.autoselect&&d&&(this._select(d),b.preventDefault());},_onTabKeyed:function(a,b){var c;(c=this.dropdown.getDatumForCursor())?(this._select(c),b.preventDefault()):this._autocomplete(!0);},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue();},_onUpKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorUp(),this.dropdown.open();},_onDownKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorDown(),this.dropdown.open();},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete();},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete();},_onQueryChanged:function(a,b){this.input.clearHintIfInvalid(),b.length>=this.minLength?this.dropdown.update(b):this.dropdown.empty(),this.dropdown.open(),this._setLanguageDirection();},_onWhitespaceChanged:function(){this._updateHint(),this.dropdown.open();},_setLanguageDirection:function(){var a;this.dir!==(a=this.input.getLanguageDirection())&&(this.dir=a,this.$node.css("direction",a),this.dropdown.setLanguageDirection(a));},_updateHint:function(){var a,c,d,e,f,g;a=this.dropdown.getDatumForTopSuggestion(),a&&this.dropdown.isVisible()&&!this.input.hasOverflow()?(c=this.input.getInputValue(),d=o.normalizeQuery(c),e=b.escapeRegExChars(d),f=new RegExp("^(?:"+e+")(.+$)","i"),g=f.exec(a.value),g?this.input.setHint(c+g[1]):this.input.clearHint()):this.input.clearHint();},_autocomplete:function(a){var b,c,d,e;b=this.input.getHint(),c=this.input.getQuery(),d=a||this.input.isCursorAtEnd(),b&&c!==b&&d&&(e=this.dropdown.getDatumForTopSuggestion(),e&&this.input.setInputValue(e.value),this.eventBus.trigger("autocompleted",e.raw,e.datasetName));},_select:function(a){this.input.setQuery(a.value),this.input.setInputValue(a.value,!0),this._setLanguageDirection(),this.eventBus.trigger("selected",a.raw,a.datasetName),this.dropdown.close(),b.defer(b.bind(this.dropdown.empty,this.dropdown));},open:function(){this.dropdown.open();},close:function(){this.dropdown.close();},setVal:function(a){this.isActivated?this.input.setInputValue(a):(this.input.setQuery(a),this.input.setInputValue(a,!0)),this._setLanguageDirection();},getVal:function(){return this.input.getQuery()},destroy:function(){this.input.destroy(),this.dropdown.destroy(),f(this.$node),this.$node=null;}}),c}();!function(){var c,d,e;c=a.fn.typeahead,d="ttTypeahead",e={initialize:function(c,e){function f(){var g,h=a(this);b.each(e,function(a){a.highlight=!!c.highlight;}),g=new r({input:h,eventBus:new l({el:h}),withHint:b.isUndefined(c.hint)?!0:!!c.hint,minLength:c.minLength,autoselect:c.autoselect,datasets:e}),h.data(d,g);}return e=b.isArray(e)?e:[].slice.call(arguments,1),c=c||{},this.each(f)},open:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.open();}return this.each(b)},close:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.close();}return this.each(b)},val:function(b){function c(){var c,e=a(this);(c=e.data(d))&&c.setVal(b);}function e(a){var b,c;return (b=a.data(d))&&(c=b.getVal()),c}return arguments.length?this.each(c):e(this.first())},destroy:function(){function b(){var b,c=a(this);(b=c.data(d))&&(b.destroy(),c.removeData(d));}return this.each(b)}},a.fn.typeahead=function(a){return e[a]?e[a].apply(this,[].slice.call(arguments,1)):e.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this};}();}(window.jQuery);
-
-/*
- * Leaflet-IIIF 3.0.0
- * IIIF Viewer for Leaflet
- * by Jack Reed, @mejackreed
- */
-
-L.TileLayer.Iiif = L.TileLayer.extend({
- options: {
- continuousWorld: true,
- tileSize: 256,
- updateWhenIdle: true,
- tileFormat: 'jpg',
- fitBounds: true,
- setMaxBounds: false
- },
-
- initialize: function(url, options) {
- options = typeof options !== 'undefined' ? options : {};
-
- if (options.maxZoom) {
- this._customMaxZoom = true;
- }
-
- // Check for explicit tileSize set
- if (options.tileSize) {
- this._explicitTileSize = true;
- }
-
- // Check for an explicit quality
- if (options.quality) {
- this._explicitQuality = true;
- }
-
- options = L.setOptions(this, options);
- this._infoPromise = null;
- this._infoUrl = url;
- this._baseUrl = this._templateUrl();
- this._getInfo();
- },
- getTileUrl: function(coords) {
- var _this = this,
- x = coords.x,
- y = (coords.y),
- zoom = _this._getZoomForUrl(),
- scale = Math.pow(2, _this.maxNativeZoom - zoom),
- tileBaseSize = _this.options.tileSize * scale,
- minx = (x * tileBaseSize),
- miny = (y * tileBaseSize),
- maxx = Math.min(minx + tileBaseSize, _this.x),
- maxy = Math.min(miny + tileBaseSize, _this.y);
-
- var xDiff = (maxx - minx);
- var yDiff = (maxy - miny);
-
- // Canonical URI Syntax for v2
- var size = Math.ceil(xDiff / scale) + ',';
- if (_this.type === 'ImageService3') {
- // Cannonical URI Syntax for v3
- size = size + Math.ceil(yDiff / scale);
- }
-
- return L.Util.template(this._baseUrl, L.extend({
- format: _this.options.tileFormat,
- quality: _this.quality,
- region: [minx, miny, xDiff, yDiff].join(','),
- rotation: 0,
- size: size
- }, this.options));
- },
- onAdd: function(map) {
- var _this = this;
-
- // Wait for info.json fetch and parse to complete
- Promise.all([_this._infoPromise]).then(function() {
- // Store unmutated imageSizes
- _this._imageSizesOriginal = _this._imageSizes.slice(0);
-
- // Set maxZoom for map
- map._layersMaxZoom = _this.maxZoom;
-
- // Call add TileLayer
- L.TileLayer.prototype.onAdd.call(_this, map);
-
- // Set minZoom and minNativeZoom based on how the imageSizes match up
- var smallestImage = _this._imageSizes[0];
- var mapSize = _this._map.getSize();
- var newMinZoom = 0;
- // Loop back through 5 times to see if a better fit can be found.
- for (var i = 1; i <= 5; i++) {
- if (smallestImage.x > mapSize.x || smallestImage.y > mapSize.y) {
- smallestImage = smallestImage.divideBy(2);
- _this._imageSizes.unshift(smallestImage);
- newMinZoom = -i;
- } else {
- break;
- }
- }
- _this.options.minZoom = newMinZoom;
- _this.options.minNativeZoom = newMinZoom;
- _this._prev_map_layersMinZoom = _this._map._layersMinZoom;
- _this._map._layersMinZoom = newMinZoom;
-
- if (_this.options.fitBounds) {
- _this._fitBounds();
- }
-
- if(_this.options.setMaxBounds) {
- _this._setMaxBounds();
- }
-
- // Reset tile sizes to handle non 256x256 IIIF tiles
- _this.on('tileload', function(tile, url) {
-
- var height = tile.tile.naturalHeight,
- width = tile.tile.naturalWidth;
-
- // No need to resize if tile is 256 x 256
- if (height === 256 && width === 256) return;
-
- tile.tile.style.width = width + 'px';
- tile.tile.style.height = height + 'px';
-
- });
- })
- .catch(function(err){
- console.error(err);
- });
- },
- onRemove: function(map) {
- var _this = this;
-
- map._layersMinZoom = _this._prev_map_layersMinZoom;
- _this._imageSizes = _this._imageSizesOriginal;
-
- // Remove maxBounds set for this image
- if(_this.options.setMaxBounds) {
- map.setMaxBounds(null);
- }
-
- // Call remove TileLayer
- L.TileLayer.prototype.onRemove.call(_this, map);
-
- },
- _fitBounds: function() {
- var _this = this;
-
- // Find best zoom level and center map
- var initialZoom = _this._getInitialZoom(_this._map.getSize());
- var offset = _this._imageSizes.length - 1 - _this.options.maxNativeZoom;
- var imageSize = _this._imageSizes[initialZoom + offset];
- var sw = _this._map.options.crs.pointToLatLng(L.point(0, imageSize.y), initialZoom);
- var ne = _this._map.options.crs.pointToLatLng(L.point(imageSize.x, 0), initialZoom);
- var bounds = L.latLngBounds(sw, ne);
-
- _this._map.fitBounds(bounds, true);
- },
- _setMaxBounds: function() {
- var _this = this;
-
- // Find best zoom level, center map, and constrain viewer
- var initialZoom = _this._getInitialZoom(_this._map.getSize());
- var imageSize = _this._imageSizes[initialZoom];
- var sw = _this._map.options.crs.pointToLatLng(L.point(0, imageSize.y), initialZoom);
- var ne = _this._map.options.crs.pointToLatLng(L.point(imageSize.x, 0), initialZoom);
- var bounds = L.latLngBounds(sw, ne);
-
- _this._map.setMaxBounds(bounds, true);
- },
- _getInfo: function() {
- var _this = this;
-
- _this._infoPromise = fetch(_this._infoUrl)
- .then(function(response) {
- return response.json();
- })
- .catch(function(err){
- console.error(err);
- })
- .then(function(data) {
- _this.y = data.height;
- _this.x = data.width;
-
- var tierSizes = [],
- imageSizes = [],
- scale,
- width_,
- height_,
- tilesX_,
- tilesY_;
-
- // Set quality based off of IIIF version
- if (data.profile instanceof Array) {
- _this.profile = data.profile[0];
- }else {
- _this.profile = data.profile;
- }
- _this.type = data.type;
-
- _this._setQuality();
-
- // Unless an explicit tileSize is set, use a preferred tileSize
- if (!_this._explicitTileSize) {
- // Set the default first
- _this.options.tileSize = 256;
- if (data.tiles) {
- // Image API 2.0 Case
- _this.options.tileSize = data.tiles[0].width;
- } else if (data.tile_width){
- // Image API 1.1 Case
- _this.options.tileSize = data.tile_width;
- }
- }
-
- function ceilLog2(x) {
- return Math.ceil(Math.log(x) / Math.LN2);
- }
- // Calculates maximum native zoom for the layer
- _this.maxNativeZoom = Math.max(
- ceilLog2(_this.x / _this.options.tileSize),
- ceilLog2(_this.y / _this.options.tileSize),
- 0
- );
- _this.options.maxNativeZoom = _this.maxNativeZoom;
-
- // Enable zooming further than native if maxZoom option supplied
- if (_this._customMaxZoom && _this.options.maxZoom > _this.maxNativeZoom) {
- _this.maxZoom = _this.options.maxZoom;
- }
- else {
- _this.maxZoom = _this.maxNativeZoom;
- }
-
- for (var i = 0; i <= _this.maxZoom; i++) {
- scale = Math.pow(2, _this.maxNativeZoom - i);
- width_ = Math.ceil(_this.x / scale);
- height_ = Math.ceil(_this.y / scale);
- tilesX_ = Math.ceil(width_ / _this.options.tileSize);
- tilesY_ = Math.ceil(height_ / _this.options.tileSize);
- tierSizes.push([tilesX_, tilesY_]);
- imageSizes.push(L.point(width_,height_));
- }
-
- _this._tierSizes = tierSizes;
- _this._imageSizes = imageSizes;
- })
- .catch(function(err){
- console.error(err);
- });
-
- },
-
- _setQuality: function() {
- var _this = this;
- var profileToCheck = _this.profile;
-
- if (_this._explicitQuality) {
- return;
- }
-
- // If profile is an object
- if (typeof(profileToCheck) === 'object') {
- profileToCheck = profileToCheck['@id'];
- }
-
- // Set the quality based on the IIIF compliance level
- switch (true) {
- case /^http:\/\/library.stanford.edu\/iiif\/image-api\/1.1\/compliance.html.*$/.test(profileToCheck):
- _this.options.quality = 'native';
- break;
- // Assume later profiles and set to default
- default:
- _this.options.quality = 'default';
- break;
- }
- },
-
- _infoToBaseUrl: function() {
- return this._infoUrl.replace('info.json', '');
- },
- _templateUrl: function() {
- return this._infoToBaseUrl() + '{region}/{size}/{rotation}/{quality}.{format}';
- },
- _isValidTile: function(coords) {
- var _this = this;
- var zoom = _this._getZoomForUrl();
- var sizes = _this._tierSizes[zoom];
- var x = coords.x;
- var y = coords.y;
- if (zoom < 0 && x >= 0 && y >= 0) {
- return true;
- }
-
- if (!sizes) return false;
- if (x < 0 || sizes[0] <= x || y < 0 || sizes[1] <= y) {
- return false;
- }else {
- return true;
- }
- },
- _tileShouldBeLoaded: function(coords) {
- return this._isValidTile(coords);
- },
- _getInitialZoom: function (mapSize) {
- var _this = this;
- var tolerance = 0.8;
- var imageSize;
- // Calculate an offset between the zoom levels and the array accessors
- var offset = _this._imageSizes.length - 1 - _this.options.maxNativeZoom;
- for (var i = _this._imageSizes.length - 1; i >= 0; i--) {
- imageSize = _this._imageSizes[i];
- if (imageSize.x * tolerance < mapSize.x && imageSize.y * tolerance < mapSize.y) {
- return i - offset;
- }
- }
- // return a default zoom
- return 2;
- }
-});
-
-L.tileLayer.iiif = function(url, options) {
- return new L.TileLayer.Iiif(url, options);
-};
-
-var Leaflet_Editable = {exports: {}};
-
-(function (module, exports) {
- (function (factory, window) {
- /*globals define, module, require*/
-
- // define an AMD module that relies on 'leaflet'
- {
- module.exports = factory(require$$0);
- }
-
- // attach your plugin to the global 'L' variable
- if(typeof window !== 'undefined' && window.L){
- factory(window.L);
- }
-
- }(function (L) {
- // 🍂miniclass CancelableEvent (Event objects)
- // 🍂method cancel()
- // Cancel any subsequent action.
-
- // 🍂miniclass VertexEvent (Event objects)
- // 🍂property vertex: VertexMarker
- // The vertex that fires the event.
-
- // 🍂miniclass ShapeEvent (Event objects)
- // 🍂property shape: Array
- // The shape (LatLngs array) subject of the action.
-
- // 🍂miniclass CancelableVertexEvent (Event objects)
- // 🍂inherits VertexEvent
- // 🍂inherits CancelableEvent
-
- // 🍂miniclass CancelableShapeEvent (Event objects)
- // 🍂inherits ShapeEvent
- // 🍂inherits CancelableEvent
-
- // 🍂miniclass LayerEvent (Event objects)
- // 🍂property layer: object
- // The Layer (Marker, Polyline…) subject of the action.
-
- // 🍂namespace Editable; 🍂class Editable; 🍂aka L.Editable
- // Main edition handler. By default, it is attached to the map
- // as `map.editTools` property.
- // Leaflet.Editable is made to be fully extendable. You have three ways to customize
- // the behaviour: using options, listening to events, or extending.
- L.Editable = L.Evented.extend({
-
- statics: {
- FORWARD: 1,
- BACKWARD: -1
- },
-
- options: {
-
- // You can pass them when creating a map using the `editOptions` key.
- // 🍂option zIndex: int = 1000
- // The default zIndex of the editing tools.
- zIndex: 1000,
-
- // 🍂option polygonClass: class = L.Polygon
- // Class to be used when creating a new Polygon.
- polygonClass: L.Polygon,
-
- // 🍂option polylineClass: class = L.Polyline
- // Class to be used when creating a new Polyline.
- polylineClass: L.Polyline,
-
- // 🍂option markerClass: class = L.Marker
- // Class to be used when creating a new Marker.
- markerClass: L.Marker,
-
- // 🍂option rectangleClass: class = L.Rectangle
- // Class to be used when creating a new Rectangle.
- rectangleClass: L.Rectangle,
-
- // 🍂option circleClass: class = L.Circle
- // Class to be used when creating a new Circle.
- circleClass: L.Circle,
-
- // 🍂option drawingCSSClass: string = 'leaflet-editable-drawing'
- // CSS class to be added to the map container while drawing.
- drawingCSSClass: 'leaflet-editable-drawing',
-
- // 🍂option drawingCursor: const = 'crosshair'
- // Cursor mode set to the map while drawing.
- drawingCursor: 'crosshair',
-
- // 🍂option editLayer: Layer = new L.LayerGroup()
- // Layer used to store edit tools (vertex, line guide…).
- editLayer: undefined,
-
- // 🍂option featuresLayer: Layer = new L.LayerGroup()
- // Default layer used to store drawn features (Marker, Polyline…).
- featuresLayer: undefined,
-
- // 🍂option polylineEditorClass: class = PolylineEditor
- // Class to be used as Polyline editor.
- polylineEditorClass: undefined,
-
- // 🍂option polygonEditorClass: class = PolygonEditor
- // Class to be used as Polygon editor.
- polygonEditorClass: undefined,
-
- // 🍂option markerEditorClass: class = MarkerEditor
- // Class to be used as Marker editor.
- markerEditorClass: undefined,
-
- // 🍂option rectangleEditorClass: class = RectangleEditor
- // Class to be used as Rectangle editor.
- rectangleEditorClass: undefined,
-
- // 🍂option circleEditorClass: class = CircleEditor
- // Class to be used as Circle editor.
- circleEditorClass: undefined,
-
- // 🍂option lineGuideOptions: hash = {}
- // Options to be passed to the line guides.
- lineGuideOptions: {},
-
- // 🍂option skipMiddleMarkers: boolean = false
- // Set this to true if you don't want middle markers.
- skipMiddleMarkers: false
-
- },
-
- initialize: function (map, options) {
- L.setOptions(this, options);
- this._lastZIndex = this.options.zIndex;
- this.map = map;
- this.editLayer = this.createEditLayer();
- this.featuresLayer = this.createFeaturesLayer();
- this.forwardLineGuide = this.createLineGuide();
- this.backwardLineGuide = this.createLineGuide();
- },
-
- fireAndForward: function (type, e) {
- e = e || {};
- e.editTools = this;
- this.fire(type, e);
- this.map.fire(type, e);
- },
-
- createLineGuide: function () {
- var options = L.extend({dashArray: '5,10', weight: 1, interactive: false}, this.options.lineGuideOptions);
- return L.polyline([], options);
- },
-
- createVertexIcon: function (options) {
- return L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options);
- },
-
- createEditLayer: function () {
- return this.options.editLayer || new L.LayerGroup().addTo(this.map);
- },
-
- createFeaturesLayer: function () {
- return this.options.featuresLayer || new L.LayerGroup().addTo(this.map);
- },
-
- moveForwardLineGuide: function (latlng) {
- if (this.forwardLineGuide._latlngs.length) {
- this.forwardLineGuide._latlngs[1] = latlng;
- this.forwardLineGuide._bounds.extend(latlng);
- this.forwardLineGuide.redraw();
- }
- },
-
- moveBackwardLineGuide: function (latlng) {
- if (this.backwardLineGuide._latlngs.length) {
- this.backwardLineGuide._latlngs[1] = latlng;
- this.backwardLineGuide._bounds.extend(latlng);
- this.backwardLineGuide.redraw();
- }
- },
-
- anchorForwardLineGuide: function (latlng) {
- this.forwardLineGuide._latlngs[0] = latlng;
- this.forwardLineGuide._bounds.extend(latlng);
- this.forwardLineGuide.redraw();
- },
-
- anchorBackwardLineGuide: function (latlng) {
- this.backwardLineGuide._latlngs[0] = latlng;
- this.backwardLineGuide._bounds.extend(latlng);
- this.backwardLineGuide.redraw();
- },
-
- attachForwardLineGuide: function () {
- this.editLayer.addLayer(this.forwardLineGuide);
- },
-
- attachBackwardLineGuide: function () {
- this.editLayer.addLayer(this.backwardLineGuide);
- },
-
- detachForwardLineGuide: function () {
- this.forwardLineGuide.setLatLngs([]);
- this.editLayer.removeLayer(this.forwardLineGuide);
- },
-
- detachBackwardLineGuide: function () {
- this.backwardLineGuide.setLatLngs([]);
- this.editLayer.removeLayer(this.backwardLineGuide);
- },
-
- blockEvents: function () {
- // Hack: force map not to listen to other layers events while drawing.
- if (!this._oldTargets) {
- this._oldTargets = this.map._targets;
- this.map._targets = {};
- }
- },
-
- unblockEvents: function () {
- if (this._oldTargets) {
- // Reset, but keep targets created while drawing.
- this.map._targets = L.extend(this.map._targets, this._oldTargets);
- delete this._oldTargets;
- }
- },
-
- registerForDrawing: function (editor) {
- if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor);
- this.blockEvents();
- editor.reset(); // Make sure editor tools still receive events.
- this._drawingEditor = editor;
- this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor);
- this.map.on('mousedown', this.onMousedown, this);
- this.map.on('mouseup', this.onMouseup, this);
- L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass);
- this.defaultMapCursor = this.map._container.style.cursor;
- this.map._container.style.cursor = this.options.drawingCursor;
- },
-
- unregisterForDrawing: function (editor) {
- this.unblockEvents();
- L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass);
- this.map._container.style.cursor = this.defaultMapCursor;
- editor = editor || this._drawingEditor;
- if (!editor) return;
- this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor);
- this.map.off('mousedown', this.onMousedown, this);
- this.map.off('mouseup', this.onMouseup, this);
- if (editor !== this._drawingEditor) return;
- delete this._drawingEditor;
- if (editor._drawing) editor.cancelDrawing();
- },
-
- onMousedown: function (e) {
- this._mouseDown = e;
- this._drawingEditor.onDrawingMouseDown(e);
- },
-
- onMouseup: function (e) {
- if (this._mouseDown) {
- var editor = this._drawingEditor,
- mouseDown = this._mouseDown;
- this._mouseDown = null;
- editor.onDrawingMouseUp(e);
- if (this._drawingEditor !== editor) return; // onDrawingMouseUp may call unregisterFromDrawing.
- var origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY);
- var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin);
- if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e);
- }
- },
-
- // 🍂section Public methods
- // You will generally access them by the `map.editTools`
- // instance:
- //
- // `map.editTools.startPolyline();`
-
- // 🍂method drawing(): boolean
- // Return true if any drawing action is ongoing.
- drawing: function () {
- return this._drawingEditor && this._drawingEditor.drawing();
- },
-
- // 🍂method stopDrawing()
- // When you need to stop any ongoing drawing, without needing to know which editor is active.
- stopDrawing: function () {
- this.unregisterForDrawing();
- },
-
- // 🍂method commitDrawing()
- // When you need to commit any ongoing drawing, without needing to know which editor is active.
- commitDrawing: function (e) {
- if (!this._drawingEditor) return;
- this._drawingEditor.commitDrawing(e);
- },
-
- connectCreatedToMap: function (layer) {
- return this.featuresLayer.addLayer(layer);
- },
-
- // 🍂method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
- // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
- // If `options` is given, it will be passed to the Polyline class constructor.
- startPolyline: function (latlng, options) {
- var line = this.createPolyline([], options);
- line.enableEdit(this.map).newShape(latlng);
- return line;
- },
-
- // 🍂method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
- // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
- // If `options` is given, it will be passed to the Polygon class constructor.
- startPolygon: function (latlng, options) {
- var polygon = this.createPolygon([], options);
- polygon.enableEdit(this.map).newShape(latlng);
- return polygon;
- },
-
- // 🍂method startMarker(latlng: L.LatLng, options: hash): L.Marker
- // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
- // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
- // If `options` is given, it will be passed to the Marker class constructor.
- startMarker: function (latlng, options) {
- latlng = latlng || this.map.getCenter().clone();
- var marker = this.createMarker(latlng, options);
- marker.enableEdit(this.map).startDrawing();
- return marker;
- },
-
- // 🍂method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
- // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
- // If `options` is given, it will be passed to the Rectangle class constructor.
- startRectangle: function(latlng, options) {
- var corner = latlng || L.latLng([0, 0]);
- var bounds = new L.LatLngBounds(corner, corner);
- var rectangle = this.createRectangle(bounds, options);
- rectangle.enableEdit(this.map).startDrawing();
- return rectangle;
- },
-
- // 🍂method startCircle(latlng: L.LatLng, options: hash): L.Circle
- // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
- // If `options` is given, it will be passed to the Circle class constructor.
- startCircle: function (latlng, options) {
- latlng = latlng || this.map.getCenter().clone();
- var circle = this.createCircle(latlng, options);
- circle.enableEdit(this.map).startDrawing();
- return circle;
- },
-
- startHole: function (editor, latlng) {
- editor.newHole(latlng);
- },
-
- createLayer: function (klass, latlngs, options) {
- options = L.Util.extend({editOptions: {editTools: this}}, options);
- var layer = new klass(latlngs, options);
- // 🍂namespace Editable
- // 🍂event editable:created: LayerEvent
- // Fired when a new feature (Marker, Polyline…) is created.
- this.fireAndForward('editable:created', {layer: layer});
- return layer;
- },
-
- createPolyline: function (latlngs, options) {
- return this.createLayer(options && options.polylineClass || this.options.polylineClass, latlngs, options);
- },
-
- createPolygon: function (latlngs, options) {
- return this.createLayer(options && options.polygonClass || this.options.polygonClass, latlngs, options);
- },
-
- createMarker: function (latlng, options) {
- return this.createLayer(options && options.markerClass || this.options.markerClass, latlng, options);
- },
-
- createRectangle: function (bounds, options) {
- return this.createLayer(options && options.rectangleClass || this.options.rectangleClass, bounds, options);
- },
-
- createCircle: function (latlng, options) {
- return this.createLayer(options && options.circleClass || this.options.circleClass, latlng, options);
- }
-
- });
-
- L.extend(L.Editable, {
-
- makeCancellable: function (e) {
- e.cancel = function () {
- e._cancelled = true;
- };
- }
-
- });
-
- // 🍂namespace Map; 🍂class Map
- // Leaflet.Editable add options and events to the `L.Map` object.
- // See `Editable` events for the list of events fired on the Map.
- // 🍂example
- //
- // ```js
- // var map = L.map('map', {
- // editable: true,
- // editOptions: {
- // …
- // }
- // });
- // ```
- // 🍂section Editable Map Options
- L.Map.mergeOptions({
-
- // 🍂namespace Map
- // 🍂section Map Options
- // 🍂option editToolsClass: class = L.Editable
- // Class to be used as vertex, for path editing.
- editToolsClass: L.Editable,
-
- // 🍂option editable: boolean = false
- // Whether to create a L.Editable instance at map init.
- editable: false,
-
- // 🍂option editOptions: hash = {}
- // Options to pass to L.Editable when instanciating.
- editOptions: {}
-
- });
-
- L.Map.addInitHook(function () {
-
- this.whenReady(function () {
- if (this.options.editable) {
- this.editTools = new this.options.editToolsClass(this, this.options.editOptions);
- }
- });
-
- });
-
- L.Editable.VertexIcon = L.DivIcon.extend({
-
- options: {
- iconSize: new L.Point(8, 8)
- }
-
- });
-
- L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
-
- options: {
- iconSize: new L.Point(20, 20)
- }
-
- });
-
-
- // 🍂namespace Editable; 🍂class VertexMarker; Handler for dragging path vertices.
- L.Editable.VertexMarker = L.Marker.extend({
-
- options: {
- draggable: true,
- className: 'leaflet-div-icon leaflet-vertex-icon'
- },
-
-
- // 🍂section Public methods
- // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
- // instance when listening for events like `editable:vertex:ctrlclick`.
-
- initialize: function (latlng, latlngs, editor, options) {
- // We don't use this._latlng, because on drag Leaflet replace it while
- // we want to keep reference.
- this.latlng = latlng;
- this.latlngs = latlngs;
- this.editor = editor;
- L.Marker.prototype.initialize.call(this, latlng, options);
- this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
- this.latlng.__vertex = this;
- this.editor.editLayer.addLayer(this);
- this.setZIndexOffset(editor.tools._lastZIndex + 1);
- },
-
- onAdd: function (map) {
- L.Marker.prototype.onAdd.call(this, map);
- this.on('drag', this.onDrag);
- this.on('dragstart', this.onDragStart);
- this.on('dragend', this.onDragEnd);
- this.on('mouseup', this.onMouseup);
- this.on('click', this.onClick);
- this.on('contextmenu', this.onContextMenu);
- this.on('mousedown touchstart', this.onMouseDown);
- this.addMiddleMarkers();
- },
-
- onRemove: function (map) {
- if (this.middleMarker) this.middleMarker.delete();
- delete this.latlng.__vertex;
- this.off('drag', this.onDrag);
- this.off('dragstart', this.onDragStart);
- this.off('dragend', this.onDragEnd);
- this.off('mouseup', this.onMouseup);
- this.off('click', this.onClick);
- this.off('contextmenu', this.onContextMenu);
- this.off('mousedown touchstart', this.onMouseDown);
- L.Marker.prototype.onRemove.call(this, map);
- },
-
- onDrag: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerDrag(e);
- var iconPos = L.DomUtil.getPosition(this._icon),
- latlng = this._map.layerPointToLatLng(iconPos);
- this.latlng.update(latlng);
- this._latlng = this.latlng; // Push back to Leaflet our reference.
- this.editor.refresh();
- if (this.middleMarker) this.middleMarker.updateLatLng();
- var next = this.getNext();
- if (next && next.middleMarker) next.middleMarker.updateLatLng();
- },
-
- onDragStart: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerDragStart(e);
- },
-
- onDragEnd: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerDragEnd(e);
- },
-
- onClick: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerClick(e);
- },
-
- onMouseup: function (e) {
- L.DomEvent.stop(e);
- e.vertex = this;
- this.editor.map.fire('mouseup', e);
- },
-
- onContextMenu: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerContextMenu(e);
- },
-
- onMouseDown: function (e) {
- e.vertex = this;
- this.editor.onVertexMarkerMouseDown(e);
- },
-
- // 🍂method delete()
- // Delete a vertex and the related LatLng.
- delete: function () {
- var next = this.getNext(); // Compute before changing latlng
- this.latlngs.splice(this.getIndex(), 1);
- this.editor.editLayer.removeLayer(this);
- this.editor.onVertexDeleted({latlng: this.latlng, vertex: this});
- if (!this.latlngs.length) this.editor.deleteShape(this.latlngs);
- if (next) next.resetMiddleMarker();
- this.editor.refresh();
- },
-
- // 🍂method getIndex(): int
- // Get the index of the current vertex among others of the same LatLngs group.
- getIndex: function () {
- return this.latlngs.indexOf(this.latlng);
- },
-
- // 🍂method getLastIndex(): int
- // Get last vertex index of the LatLngs group of the current vertex.
- getLastIndex: function () {
- return this.latlngs.length - 1;
- },
-
- // 🍂method getPrevious(): VertexMarker
- // Get the previous VertexMarker in the same LatLngs group.
- getPrevious: function () {
- if (this.latlngs.length < 2) return;
- var index = this.getIndex(),
- previousIndex = index - 1;
- if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex();
- var previous = this.latlngs[previousIndex];
- if (previous) return previous.__vertex;
- },
-
- // 🍂method getNext(): VertexMarker
- // Get the next VertexMarker in the same LatLngs group.
- getNext: function () {
- if (this.latlngs.length < 2) return;
- var index = this.getIndex(),
- nextIndex = index + 1;
- if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0;
- var next = this.latlngs[nextIndex];
- if (next) return next.__vertex;
- },
-
- addMiddleMarker: function (previous) {
- if (!this.editor.hasMiddleMarkers()) return;
- previous = previous || this.getPrevious();
- if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor);
- },
-
- addMiddleMarkers: function () {
- if (!this.editor.hasMiddleMarkers()) return;
- var previous = this.getPrevious();
- if (previous) this.addMiddleMarker(previous);
- var next = this.getNext();
- if (next) next.resetMiddleMarker();
- },
-
- resetMiddleMarker: function () {
- if (this.middleMarker) this.middleMarker.delete();
- this.addMiddleMarker();
- },
-
- // 🍂method split()
- // Split the vertex LatLngs group at its index, if possible.
- split: function () {
- if (!this.editor.splitShape) return; // Only for PolylineEditor
- this.editor.splitShape(this.latlngs, this.getIndex());
- },
-
- // 🍂method continue()
- // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
- continue: function () {
- if (!this.editor.continueBackward) return; // Only for PolylineEditor
- var index = this.getIndex();
- if (index === 0) this.editor.continueBackward(this.latlngs);
- else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs);
- }
-
- });
-
- L.Editable.mergeOptions({
-
- // 🍂namespace Editable
- // 🍂option vertexMarkerClass: class = VertexMarker
- // Class to be used as vertex, for path editing.
- vertexMarkerClass: L.Editable.VertexMarker
-
- });
-
- L.Editable.MiddleMarker = L.Marker.extend({
-
- options: {
- opacity: 0.5,
- className: 'leaflet-div-icon leaflet-middle-icon',
- draggable: true
- },
-
- initialize: function (left, right, latlngs, editor, options) {
- this.left = left;
- this.right = right;
- this.editor = editor;
- this.latlngs = latlngs;
- L.Marker.prototype.initialize.call(this, this.computeLatLng(), options);
- this._opacity = this.options.opacity;
- this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
- this.editor.editLayer.addLayer(this);
- this.setVisibility();
- },
-
- setVisibility: function () {
- var leftPoint = this._map.latLngToContainerPoint(this.left.latlng),
- rightPoint = this._map.latLngToContainerPoint(this.right.latlng),
- size = L.point(this.options.icon.options.iconSize);
- if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide();
- else this.show();
- },
-
- show: function () {
- this.setOpacity(this._opacity);
- },
-
- hide: function () {
- this.setOpacity(0);
- },
-
- updateLatLng: function () {
- this.setLatLng(this.computeLatLng());
- this.setVisibility();
- },
-
- computeLatLng: function () {
- var leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng),
- rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng),
- y = (leftPoint.y + rightPoint.y) / 2,
- x = (leftPoint.x + rightPoint.x) / 2;
- return this.editor.map.containerPointToLatLng([x, y]);
- },
-
- onAdd: function (map) {
- L.Marker.prototype.onAdd.call(this, map);
- L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this);
- map.on('zoomend', this.setVisibility, this);
- },
-
- onRemove: function (map) {
- delete this.right.middleMarker;
- L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this);
- map.off('zoomend', this.setVisibility, this);
- L.Marker.prototype.onRemove.call(this, map);
- },
-
- onMouseDown: function (e) {
- var iconPos = L.DomUtil.getPosition(this._icon),
- latlng = this.editor.map.layerPointToLatLng(iconPos);
- e = {
- originalEvent: e,
- latlng: latlng
- };
- if (this.options.opacity === 0) return;
- L.Editable.makeCancellable(e);
- this.editor.onMiddleMarkerMouseDown(e);
- if (e._cancelled) return;
- this.latlngs.splice(this.index(), 0, e.latlng);
- this.editor.refresh();
- var icon = this._icon;
- var marker = this.editor.addVertexMarker(e.latlng, this.latlngs);
- this.editor.onNewVertex(marker);
- /* Hack to workaround browser not firing touchend when element is no more on DOM */
- var parent = marker._icon.parentNode;
- parent.removeChild(marker._icon);
- marker._icon = icon;
- parent.appendChild(marker._icon);
- marker._initIcon();
- marker._initInteraction();
- marker.setOpacity(1);
- /* End hack */
- // Transfer ongoing dragging to real marker
- L.Draggable._dragging = false;
- marker.dragging._draggable._onDown(e.originalEvent);
- this.delete();
- },
-
- delete: function () {
- this.editor.editLayer.removeLayer(this);
- },
-
- index: function () {
- return this.latlngs.indexOf(this.right.latlng);
- }
-
- });
-
- L.Editable.mergeOptions({
-
- // 🍂namespace Editable
- // 🍂option middleMarkerClass: class = VertexMarker
- // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
- middleMarkerClass: L.Editable.MiddleMarker
-
- });
-
- // 🍂namespace Editable; 🍂class BaseEditor; 🍂aka L.Editable.BaseEditor
- // When editing a feature (Marker, Polyline…), an editor is attached to it. This
- // editor basically knows how to handle the edition.
- L.Editable.BaseEditor = L.Handler.extend({
-
- initialize: function (map, feature, options) {
- L.setOptions(this, options);
- this.map = map;
- this.feature = feature;
- this.feature.editor = this;
- this.editLayer = new L.LayerGroup();
- this.tools = this.options.editTools || map.editTools;
- },
-
- // 🍂method enable(): this
- // Set up the drawing tools for the feature to be editable.
- addHooks: function () {
- if (this.isConnected()) this.onFeatureAdd();
- else this.feature.once('add', this.onFeatureAdd, this);
- this.onEnable();
- this.feature.on(this._getEvents(), this);
- return;
- },
-
- // 🍂method disable(): this
- // Remove the drawing tools for the feature.
- removeHooks: function () {
- this.feature.off(this._getEvents(), this);
- if (this.feature.dragging) this.feature.dragging.disable();
- this.editLayer.clearLayers();
- this.tools.editLayer.removeLayer(this.editLayer);
- this.onDisable();
- if (this._drawing) this.cancelDrawing();
- return;
- },
-
- // 🍂method drawing(): boolean
- // Return true if any drawing action is ongoing with this editor.
- drawing: function () {
- return !!this._drawing;
- },
-
- reset: function () {},
-
- onFeatureAdd: function () {
- this.tools.editLayer.addLayer(this.editLayer);
- if (this.feature.dragging) this.feature.dragging.enable();
- },
-
- hasMiddleMarkers: function () {
- return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers;
- },
-
- fireAndForward: function (type, e) {
- e = e || {};
- e.layer = this.feature;
- this.feature.fire(type, e);
- this.tools.fireAndForward(type, e);
- },
-
- onEnable: function () {
- // 🍂namespace Editable
- // 🍂event editable:enable: Event
- // Fired when an existing feature is ready to be edited.
- this.fireAndForward('editable:enable');
- },
-
- onDisable: function () {
- // 🍂namespace Editable
- // 🍂event editable:disable: Event
- // Fired when an existing feature is not ready anymore to be edited.
- this.fireAndForward('editable:disable');
- },
-
- onEditing: function () {
- // 🍂namespace Editable
- // 🍂event editable:editing: Event
- // Fired as soon as any change is made to the feature geometry.
- this.fireAndForward('editable:editing');
- },
-
- onStartDrawing: function () {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:start: Event
- // Fired when a feature is to be drawn.
- this.fireAndForward('editable:drawing:start');
- },
-
- onEndDrawing: function () {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:end: Event
- // Fired when a feature is not drawn anymore.
- this.fireAndForward('editable:drawing:end');
- },
-
- onCancelDrawing: function () {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:cancel: Event
- // Fired when user cancel drawing while a feature is being drawn.
- this.fireAndForward('editable:drawing:cancel');
- },
-
- onCommitDrawing: function (e) {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:commit: Event
- // Fired when user finish drawing a feature.
- this.fireAndForward('editable:drawing:commit', e);
- },
-
- onDrawingMouseDown: function (e) {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:mousedown: Event
- // Fired when user `mousedown` while drawing.
- this.fireAndForward('editable:drawing:mousedown', e);
- },
-
- onDrawingMouseUp: function (e) {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:mouseup: Event
- // Fired when user `mouseup` while drawing.
- this.fireAndForward('editable:drawing:mouseup', e);
- },
-
- startDrawing: function () {
- if (!this._drawing) this._drawing = L.Editable.FORWARD;
- this.tools.registerForDrawing(this);
- this.onStartDrawing();
- },
-
- commitDrawing: function (e) {
- this.onCommitDrawing(e);
- this.endDrawing();
- },
-
- cancelDrawing: function () {
- // If called during a vertex drag, the vertex will be removed before
- // the mouseup fires on it. This is a workaround. Maybe better fix is
- // To have L.Draggable reset it's status on disable (Leaflet side).
- L.Draggable._dragging = false;
- this.onCancelDrawing();
- this.endDrawing();
- },
-
- endDrawing: function () {
- this._drawing = false;
- this.tools.unregisterForDrawing(this);
- this.onEndDrawing();
- },
-
- onDrawingClick: function (e) {
- if (!this.drawing()) return;
- L.Editable.makeCancellable(e);
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:click: CancelableEvent
- // Fired when user `click` while drawing, before any internal action is being processed.
- this.fireAndForward('editable:drawing:click', e);
- if (e._cancelled) return;
- if (!this.isConnected()) this.connect(e);
- this.processDrawingClick(e);
- },
-
- isConnected: function () {
- return this.map.hasLayer(this.feature);
- },
-
- connect: function (e) {
- this.tools.connectCreatedToMap(this.feature);
- this.tools.editLayer.addLayer(this.editLayer);
- },
-
- onMove: function (e) {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:move: Event
- // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
- this.fireAndForward('editable:drawing:move', e);
- },
-
- onDrawingMouseMove: function (e) {
- this.onMove(e);
- },
-
- _getEvents: function () {
- return {
- dragstart: this.onDragStart,
- drag: this.onDrag,
- dragend: this.onDragEnd,
- remove: this.disable
- };
- },
-
- onDragStart: function (e) {
- this.onEditing();
- // 🍂namespace Editable
- // 🍂event editable:dragstart: Event
- // Fired before a path feature is dragged.
- this.fireAndForward('editable:dragstart', e);
- },
-
- onDrag: function (e) {
- this.onMove(e);
- // 🍂namespace Editable
- // 🍂event editable:drag: Event
- // Fired when a path feature is being dragged.
- this.fireAndForward('editable:drag', e);
- },
-
- onDragEnd: function (e) {
- // 🍂namespace Editable
- // 🍂event editable:dragend: Event
- // Fired after a path feature has been dragged.
- this.fireAndForward('editable:dragend', e);
- }
-
- });
-
- // 🍂namespace Editable; 🍂class MarkerEditor; 🍂aka L.Editable.MarkerEditor
- // 🍂inherits BaseEditor
- // Editor for Marker.
- L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
-
- onDrawingMouseMove: function (e) {
- L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
- if (this._drawing) this.feature.setLatLng(e.latlng);
- },
-
- processDrawingClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Drawing events
- // 🍂event editable:drawing:clicked: Event
- // Fired when user `click` while drawing, after all internal actions.
- this.fireAndForward('editable:drawing:clicked', e);
- this.commitDrawing(e);
- },
-
- connect: function (e) {
- // On touch, the latlng has not been updated because there is
- // no mousemove.
- if (e) this.feature._latlng = e.latlng;
- L.Editable.BaseEditor.prototype.connect.call(this, e);
- }
-
- });
-
- // 🍂namespace Editable; 🍂class PathEditor; 🍂aka L.Editable.PathEditor
- // 🍂inherits BaseEditor
- // Base class for all path editors.
- L.Editable.PathEditor = L.Editable.BaseEditor.extend({
-
- CLOSED: false,
- MIN_VERTEX: 2,
-
- addHooks: function () {
- L.Editable.BaseEditor.prototype.addHooks.call(this);
- if (this.feature) this.initVertexMarkers();
- return this;
- },
-
- initVertexMarkers: function (latlngs) {
- if (!this.enabled()) return;
- latlngs = latlngs || this.getLatLngs();
- if (isFlat(latlngs)) this.addVertexMarkers(latlngs);
- else for (var i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]);
- },
-
- getLatLngs: function () {
- return this.feature.getLatLngs();
- },
-
- // 🍂method reset()
- // Rebuild edit elements (Vertex, MiddleMarker, etc.).
- reset: function () {
- this.editLayer.clearLayers();
- this.initVertexMarkers();
- },
-
- addVertexMarker: function (latlng, latlngs) {
- return new this.tools.options.vertexMarkerClass(latlng, latlngs, this);
- },
-
- onNewVertex: function (vertex) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:new: VertexEvent
- // Fired when a new vertex is created.
- this.fireAndForward('editable:vertex:new', {latlng: vertex.latlng, vertex: vertex});
- },
-
- addVertexMarkers: function (latlngs) {
- for (var i = 0; i < latlngs.length; i++) {
- this.addVertexMarker(latlngs[i], latlngs);
- }
- },
-
- refreshVertexMarkers: function (latlngs) {
- latlngs = latlngs || this.getDefaultLatLngs();
- for (var i = 0; i < latlngs.length; i++) {
- latlngs[i].__vertex.update();
- }
- },
-
- addMiddleMarker: function (left, right, latlngs) {
- return new this.tools.options.middleMarkerClass(left, right, latlngs, this);
- },
-
- onVertexMarkerClick: function (e) {
- L.Editable.makeCancellable(e);
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:click: CancelableVertexEvent
- // Fired when a `click` is issued on a vertex, before any internal action is being processed.
- this.fireAndForward('editable:vertex:click', e);
- if (e._cancelled) return;
- if (this.tools.drawing() && this.tools._drawingEditor !== this) return;
- var index = e.vertex.getIndex(), commit;
- if (e.originalEvent.ctrlKey) {
- this.onVertexMarkerCtrlClick(e);
- } else if (e.originalEvent.altKey) {
- this.onVertexMarkerAltClick(e);
- } else if (e.originalEvent.shiftKey) {
- this.onVertexMarkerShiftClick(e);
- } else if (e.originalEvent.metaKey) {
- this.onVertexMarkerMetaKeyClick(e);
- } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) {
- if (index >= this.MIN_VERTEX - 1) commit = true;
- } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) {
- commit = true;
- } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) {
- commit = true; // Allow to close on first point also for polygons
- } else {
- this.onVertexRawMarkerClick(e);
- }
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:clicked: VertexEvent
- // Fired when a `click` is issued on a vertex, after all internal actions.
- this.fireAndForward('editable:vertex:clicked', e);
- if (commit) this.commitDrawing(e);
- },
-
- onVertexRawMarkerClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:rawclick: CancelableVertexEvent
- // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
- this.fireAndForward('editable:vertex:rawclick', e);
- if (e._cancelled) return;
- if (!this.vertexCanBeDeleted(e.vertex)) return;
- e.vertex.delete();
- },
-
- vertexCanBeDeleted: function (vertex) {
- return vertex.latlngs.length > this.MIN_VERTEX;
- },
-
- onVertexDeleted: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:deleted: VertexEvent
- // Fired after a vertex has been deleted by user.
- this.fireAndForward('editable:vertex:deleted', e);
- },
-
- onVertexMarkerCtrlClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:ctrlclick: VertexEvent
- // Fired when a `click` with `ctrlKey` is issued on a vertex.
- this.fireAndForward('editable:vertex:ctrlclick', e);
- },
-
- onVertexMarkerShiftClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:shiftclick: VertexEvent
- // Fired when a `click` with `shiftKey` is issued on a vertex.
- this.fireAndForward('editable:vertex:shiftclick', e);
- },
-
- onVertexMarkerMetaKeyClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:metakeyclick: VertexEvent
- // Fired when a `click` with `metaKey` is issued on a vertex.
- this.fireAndForward('editable:vertex:metakeyclick', e);
- },
-
- onVertexMarkerAltClick: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:altclick: VertexEvent
- // Fired when a `click` with `altKey` is issued on a vertex.
- this.fireAndForward('editable:vertex:altclick', e);
- },
-
- onVertexMarkerContextMenu: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:contextmenu: VertexEvent
- // Fired when a `contextmenu` is issued on a vertex.
- this.fireAndForward('editable:vertex:contextmenu', e);
- },
-
- onVertexMarkerMouseDown: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:mousedown: VertexEvent
- // Fired when user `mousedown` a vertex.
- this.fireAndForward('editable:vertex:mousedown', e);
- },
-
- onMiddleMarkerMouseDown: function (e) {
- // 🍂namespace Editable
- // 🍂section MiddleMarker events
- // 🍂event editable:middlemarker:mousedown: VertexEvent
- // Fired when user `mousedown` a middle marker.
- this.fireAndForward('editable:middlemarker:mousedown', e);
- },
-
- onVertexMarkerDrag: function (e) {
- this.onMove(e);
- if (this.feature._bounds) this.extendBounds(e);
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:drag: VertexEvent
- // Fired when a vertex is dragged by user.
- this.fireAndForward('editable:vertex:drag', e);
- },
-
- onVertexMarkerDragStart: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:dragstart: VertexEvent
- // Fired before a vertex is dragged by user.
- this.fireAndForward('editable:vertex:dragstart', e);
- },
-
- onVertexMarkerDragEnd: function (e) {
- // 🍂namespace Editable
- // 🍂section Vertex events
- // 🍂event editable:vertex:dragend: VertexEvent
- // Fired after a vertex is dragged by user.
- this.fireAndForward('editable:vertex:dragend', e);
- },
-
- setDrawnLatLngs: function (latlngs) {
- this._drawnLatLngs = latlngs || this.getDefaultLatLngs();
- },
-
- startDrawing: function () {
- if (!this._drawnLatLngs) this.setDrawnLatLngs();
- L.Editable.BaseEditor.prototype.startDrawing.call(this);
- },
-
- startDrawingForward: function () {
- this.startDrawing();
- },
-
- endDrawing: function () {
- this.tools.detachForwardLineGuide();
- this.tools.detachBackwardLineGuide();
- if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs);
- L.Editable.BaseEditor.prototype.endDrawing.call(this);
- delete this._drawnLatLngs;
- },
-
- addLatLng: function (latlng) {
- if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng);
- else this._drawnLatLngs.unshift(latlng);
- this.feature._bounds.extend(latlng);
- var vertex = this.addVertexMarker(latlng, this._drawnLatLngs);
- this.onNewVertex(vertex);
- this.refresh();
- },
-
- newPointForward: function (latlng) {
- this.addLatLng(latlng);
- this.tools.attachForwardLineGuide();
- this.tools.anchorForwardLineGuide(latlng);
- },
-
- newPointBackward: function (latlng) {
- this.addLatLng(latlng);
- this.tools.anchorBackwardLineGuide(latlng);
- },
-
- // 🍂namespace PathEditor
- // 🍂method push()
- // Programmatically add a point while drawing.
- push: function (latlng) {
- if (!latlng) return console.error('L.Editable.PathEditor.push expect a vaild latlng as parameter');
- if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng);
- else this.newPointBackward(latlng);
- },
-
- removeLatLng: function (latlng) {
- latlng.__vertex.delete();
- this.refresh();
- },
-
- // 🍂method pop(): L.LatLng or null
- // Programmatically remove last point (if any) while drawing.
- pop: function () {
- if (this._drawnLatLngs.length <= 1) return;
- var latlng;
- if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1];
- else latlng = this._drawnLatLngs[0];
- this.removeLatLng(latlng);
- if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]);
- else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]);
- return latlng;
- },
-
- processDrawingClick: function (e) {
- if (e.vertex && e.vertex.editor === this) return;
- if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng);
- else this.newPointBackward(e.latlng);
- this.fireAndForward('editable:drawing:clicked', e);
- },
-
- onDrawingMouseMove: function (e) {
- L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
- if (this._drawing) {
- this.tools.moveForwardLineGuide(e.latlng);
- this.tools.moveBackwardLineGuide(e.latlng);
- }
- },
-
- refresh: function () {
- this.feature.redraw();
- this.onEditing();
- },
-
- // 🍂namespace PathEditor
- // 🍂method newShape(latlng?: L.LatLng)
- // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
- // if optional `latlng` is given, start a path at this point.
- newShape: function (latlng) {
- var shape = this.addNewEmptyShape();
- if (!shape) return;
- this.setDrawnLatLngs(shape[0] || shape); // Polygon or polyline
- this.startDrawingForward();
- // 🍂namespace Editable
- // 🍂section Shape events
- // 🍂event editable:shape:new: ShapeEvent
- // Fired when a new shape is created in a multi (Polygon or Polyline).
- this.fireAndForward('editable:shape:new', {shape: shape});
- if (latlng) this.newPointForward(latlng);
- },
-
- deleteShape: function (shape, latlngs) {
- var e = {shape: shape};
- L.Editable.makeCancellable(e);
- // 🍂namespace Editable
- // 🍂section Shape events
- // 🍂event editable:shape:delete: CancelableShapeEvent
- // Fired before a new shape is deleted in a multi (Polygon or Polyline).
- this.fireAndForward('editable:shape:delete', e);
- if (e._cancelled) return;
- shape = this._deleteShape(shape, latlngs);
- if (this.ensureNotFlat) this.ensureNotFlat(); // Polygon.
- this.feature.setLatLngs(this.getLatLngs()); // Force bounds reset.
- this.refresh();
- this.reset();
- // 🍂namespace Editable
- // 🍂section Shape events
- // 🍂event editable:shape:deleted: ShapeEvent
- // Fired after a new shape is deleted in a multi (Polygon or Polyline).
- this.fireAndForward('editable:shape:deleted', {shape: shape});
- return shape;
- },
-
- _deleteShape: function (shape, latlngs) {
- latlngs = latlngs || this.getLatLngs();
- if (!latlngs.length) return;
- var self = this,
- inplaceDelete = function (latlngs, shape) {
- // Called when deleting a flat latlngs
- shape = latlngs.splice(0, Number.MAX_VALUE);
- return shape;
- },
- spliceDelete = function (latlngs, shape) {
- // Called when removing a latlngs inside an array
- latlngs.splice(latlngs.indexOf(shape), 1);
- if (!latlngs.length) self._deleteShape(latlngs);
- return shape;
- };
- if (latlngs === shape) return inplaceDelete(latlngs, shape);
- for (var i = 0; i < latlngs.length; i++) {
- if (latlngs[i] === shape) return spliceDelete(latlngs, shape);
- else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape);
- }
- },
-
- // 🍂namespace PathEditor
- // 🍂method deleteShapeAt(latlng: L.LatLng): Array
- // Remove a path shape at the given `latlng`.
- deleteShapeAt: function (latlng) {
- var shape = this.feature.shapeAt(latlng);
- if (shape) return this.deleteShape(shape);
- },
-
- // 🍂method appendShape(shape: Array)
- // Append a new shape to the Polygon or Polyline.
- appendShape: function (shape) {
- this.insertShape(shape);
- },
-
- // 🍂method prependShape(shape: Array)
- // Prepend a new shape to the Polygon or Polyline.
- prependShape: function (shape) {
- this.insertShape(shape, 0);
- },
-
- // 🍂method insertShape(shape: Array, index: int)
- // Insert a new shape to the Polygon or Polyline at given index (default is to append).
- insertShape: function (shape, index) {
- this.ensureMulti();
- shape = this.formatShape(shape);
- if (typeof index === 'undefined') index = this.feature._latlngs.length;
- this.feature._latlngs.splice(index, 0, shape);
- this.feature.redraw();
- if (this._enabled) this.reset();
- },
-
- extendBounds: function (e) {
- this.feature._bounds.extend(e.vertex.latlng);
- },
-
- onDragStart: function (e) {
- this.editLayer.clearLayers();
- L.Editable.BaseEditor.prototype.onDragStart.call(this, e);
- },
-
- onDragEnd: function (e) {
- this.initVertexMarkers();
- L.Editable.BaseEditor.prototype.onDragEnd.call(this, e);
- }
-
- });
-
- // 🍂namespace Editable; 🍂class PolylineEditor; 🍂aka L.Editable.PolylineEditor
- // 🍂inherits PathEditor
- L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
-
- startDrawingBackward: function () {
- this._drawing = L.Editable.BACKWARD;
- this.startDrawing();
- },
-
- // 🍂method continueBackward(latlngs?: Array)
- // Set up drawing tools to continue the line backward.
- continueBackward: function (latlngs) {
- if (this.drawing()) return;
- latlngs = latlngs || this.getDefaultLatLngs();
- this.setDrawnLatLngs(latlngs);
- if (latlngs.length > 0) {
- this.tools.attachBackwardLineGuide();
- this.tools.anchorBackwardLineGuide(latlngs[0]);
- }
- this.startDrawingBackward();
- },
-
- // 🍂method continueForward(latlngs?: Array)
- // Set up drawing tools to continue the line forward.
- continueForward: function (latlngs) {
- if (this.drawing()) return;
- latlngs = latlngs || this.getDefaultLatLngs();
- this.setDrawnLatLngs(latlngs);
- if (latlngs.length > 0) {
- this.tools.attachForwardLineGuide();
- this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]);
- }
- this.startDrawingForward();
- },
-
- getDefaultLatLngs: function (latlngs) {
- latlngs = latlngs || this.feature._latlngs;
- if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs;
- else return this.getDefaultLatLngs(latlngs[0]);
- },
-
- ensureMulti: function () {
- if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
- this.feature._latlngs = [this.feature._latlngs];
- }
- },
-
- addNewEmptyShape: function () {
- if (this.feature._latlngs.length) {
- var shape = [];
- this.appendShape(shape);
- return shape;
- } else {
- return this.feature._latlngs;
- }
- },
-
- formatShape: function (shape) {
- if (isFlat(shape)) return shape;
- else if (shape[0]) return this.formatShape(shape[0]);
- },
-
- // 🍂method splitShape(latlngs?: Array, index: int)
- // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
- splitShape: function (shape, index) {
- if (!index || index >= shape.length - 1) return;
- this.ensureMulti();
- var shapeIndex = this.feature._latlngs.indexOf(shape);
- if (shapeIndex === -1) return;
- var first = shape.slice(0, index + 1),
- second = shape.slice(index);
- // We deal with reference, we don't want twice the same latlng around.
- second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt);
- this.feature._latlngs.splice(shapeIndex, 1, first, second);
- this.refresh();
- this.reset();
- }
-
- });
-
- // 🍂namespace Editable; 🍂class PolygonEditor; 🍂aka L.Editable.PolygonEditor
- // 🍂inherits PathEditor
- L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
-
- CLOSED: true,
- MIN_VERTEX: 3,
-
- newPointForward: function (latlng) {
- L.Editable.PathEditor.prototype.newPointForward.call(this, latlng);
- if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng);
- if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide();
- },
-
- addNewEmptyHole: function (latlng) {
- this.ensureNotFlat();
- var latlngs = this.feature.shapeAt(latlng);
- if (!latlngs) return;
- var holes = [];
- latlngs.push(holes);
- return holes;
- },
-
- // 🍂method newHole(latlng?: L.LatLng, index: int)
- // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
- newHole: function (latlng) {
- var holes = this.addNewEmptyHole(latlng);
- if (!holes) return;
- this.setDrawnLatLngs(holes);
- this.startDrawingForward();
- if (latlng) this.newPointForward(latlng);
- },
-
- addNewEmptyShape: function () {
- if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
- var shape = [];
- this.appendShape(shape);
- return shape;
- } else {
- return this.feature._latlngs;
- }
- },
-
- ensureMulti: function () {
- if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
- this.feature._latlngs = [this.feature._latlngs];
- }
- },
-
- ensureNotFlat: function () {
- if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs];
- },
-
- vertexCanBeDeleted: function (vertex) {
- var parent = this.feature.parentShape(vertex.latlngs),
- idx = L.Util.indexOf(parent, vertex.latlngs);
- if (idx > 0) return true; // Holes can be totally deleted without removing the layer itself.
- return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex);
- },
-
- getDefaultLatLngs: function () {
- if (!this.feature._latlngs.length) this.feature._latlngs.push([]);
- return this.feature._latlngs[0];
- },
-
- formatShape: function (shape) {
- // [[1, 2], [3, 4]] => must be nested
- // [] => must be nested
- // [[]] => is already nested
- if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape];
- else return shape;
- }
-
- });
-
- // 🍂namespace Editable; 🍂class RectangleEditor; 🍂aka L.Editable.RectangleEditor
- // 🍂inherits PathEditor
- L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
-
- CLOSED: true,
- MIN_VERTEX: 4,
-
- options: {
- skipMiddleMarkers: true
- },
-
- extendBounds: function (e) {
- var index = e.vertex.getIndex(),
- next = e.vertex.getNext(),
- previous = e.vertex.getPrevious(),
- oppositeIndex = (index + 2) % 4,
- opposite = e.vertex.latlngs[oppositeIndex],
- bounds = new L.LatLngBounds(e.latlng, opposite);
- // Update latlngs by hand to preserve order.
- previous.latlng.update([e.latlng.lat, opposite.lng]);
- next.latlng.update([opposite.lat, e.latlng.lng]);
- this.updateBounds(bounds);
- this.refreshVertexMarkers();
- },
-
- onDrawingMouseDown: function (e) {
- L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
- this.connect();
- var latlngs = this.getDefaultLatLngs();
- // L.Polygon._convertLatLngs removes last latlng if it equals first point,
- // which is the case here as all latlngs are [0, 0]
- if (latlngs.length === 3) latlngs.push(e.latlng);
- var bounds = new L.LatLngBounds(e.latlng, e.latlng);
- this.updateBounds(bounds);
- this.updateLatLngs(bounds);
- this.refresh();
- this.reset();
- // Stop dragging map.
- // L.Draggable has two workflows:
- // - mousedown => mousemove => mouseup
- // - touchstart => touchmove => touchend
- // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
- // can deal with mousedown, but then when in a touch device, we are dealing with
- // simulated events (actually simulated by L.Map.Tap), which are no more taken
- // into account by L.Draggable.
- // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
- e.originalEvent._simulated = false;
- this.map.dragging._draggable._onUp(e.originalEvent);
- // Now transfer ongoing drag action to the bottom right corner.
- // Should we refine which corne will handle the drag according to
- // drag direction?
- latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent);
- },
-
- onDrawingMouseUp: function (e) {
- this.commitDrawing(e);
- e.originalEvent._simulated = false;
- L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
- },
-
- onDrawingMouseMove: function (e) {
- e.originalEvent._simulated = false;
- L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
- },
-
-
- getDefaultLatLngs: function (latlngs) {
- return latlngs || this.feature._latlngs[0];
- },
-
- updateBounds: function (bounds) {
- this.feature._bounds = bounds;
- },
-
- updateLatLngs: function (bounds) {
- var latlngs = this.getDefaultLatLngs(),
- newLatlngs = this.feature._boundsToLatLngs(bounds);
- // Keep references.
- for (var i = 0; i < latlngs.length; i++) {
- latlngs[i].update(newLatlngs[i]);
- } }
-
- });
-
- // 🍂namespace Editable; 🍂class CircleEditor; 🍂aka L.Editable.CircleEditor
- // 🍂inherits PathEditor
- L.Editable.CircleEditor = L.Editable.PathEditor.extend({
-
- MIN_VERTEX: 2,
-
- options: {
- skipMiddleMarkers: true
- },
-
- initialize: function (map, feature, options) {
- L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options);
- this._resizeLatLng = this.computeResizeLatLng();
- },
-
- computeResizeLatLng: function () {
- // While circle is not added to the map, _radius is not set.
- var delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4),
- point = this.map.project(this.feature._latlng);
- return this.map.unproject([point.x + delta, point.y - delta]);
- },
-
- updateResizeLatLng: function () {
- this._resizeLatLng.update(this.computeResizeLatLng());
- this._resizeLatLng.__vertex.update();
- },
-
- getLatLngs: function () {
- return [this.feature._latlng, this._resizeLatLng];
- },
-
- getDefaultLatLngs: function () {
- return this.getLatLngs();
- },
-
- onVertexMarkerDrag: function (e) {
- if (e.vertex.getIndex() === 1) this.resize(e);
- else this.updateResizeLatLng(e);
- L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e);
- },
-
- resize: function (e) {
- var radius = this.feature._latlng.distanceTo(e.latlng);
- this.feature.setRadius(radius);
- },
-
- onDrawingMouseDown: function (e) {
- L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
- this._resizeLatLng.update(e.latlng);
- this.feature._latlng.update(e.latlng);
- this.connect();
- // Stop dragging map.
- e.originalEvent._simulated = false;
- this.map.dragging._draggable._onUp(e.originalEvent);
- // Now transfer ongoing drag action to the radius handler.
- this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent);
- },
-
- onDrawingMouseUp: function (e) {
- this.commitDrawing(e);
- e.originalEvent._simulated = false;
- L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
- },
-
- onDrawingMouseMove: function (e) {
- e.originalEvent._simulated = false;
- L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
- },
-
- onDrag: function (e) {
- L.Editable.PathEditor.prototype.onDrag.call(this, e);
- this.feature.dragging.updateLatLng(this._resizeLatLng);
- }
-
- });
-
- // 🍂namespace Editable; 🍂class EditableMixin
- // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
- // and `L.Marker`. It adds some methods to them.
- // *When editing is enabled, the editor is accessible on the instance with the
- // `editor` property.*
- var EditableMixin = {
-
- createEditor: function (map) {
- map = map || this._map;
- var tools = (this.options.editOptions || {}).editTools || map.editTools;
- if (!tools) throw Error('Unable to detect Editable instance.')
- var Klass = this.options.editorClass || this.getEditorClass(tools);
- return new Klass(map, this, this.options.editOptions);
- },
-
- // 🍂method enableEdit(map?: L.Map): this.editor
- // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
- enableEdit: function (map) {
- if (!this.editor) this.createEditor(map);
- this.editor.enable();
- return this.editor;
- },
-
- // 🍂method editEnabled(): boolean
- // Return true if current instance has an editor attached, and this editor is enabled.
- editEnabled: function () {
- return this.editor && this.editor.enabled();
- },
-
- // 🍂method disableEdit()
- // Disable editing, also remove the editor property reference.
- disableEdit: function () {
- if (this.editor) {
- this.editor.disable();
- delete this.editor;
- }
- },
-
- // 🍂method toggleEdit()
- // Enable or disable editing, according to current status.
- toggleEdit: function () {
- if (this.editEnabled()) this.disableEdit();
- else this.enableEdit();
- },
-
- _onEditableAdd: function () {
- if (this.editor) this.enableEdit();
- }
-
- };
-
- var PolylineMixin = {
-
- getEditorClass: function (tools) {
- return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor;
- },
-
- shapeAt: function (latlng, latlngs) {
- // We can have those cases:
- // - latlngs are just a flat array of latlngs, use this
- // - latlngs is an array of arrays of latlngs, loop over
- var shape = null;
- latlngs = latlngs || this._latlngs;
- if (!latlngs.length) return shape;
- else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
- else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i];
- return shape;
- },
-
- isInLatLngs: function (l, latlngs) {
- if (!latlngs) return false;
- var i, k, len, part = [], p,
- w = this._clickTolerance();
- this._projectLatlngs(latlngs, part, this._pxBounds);
- part = part[0];
- p = this._map.latLngToLayerPoint(l);
-
- if (!this._pxBounds.contains(p)) { return false; }
- for (i = 1, len = part.length, k = 0; i < len; k = i++) {
-
- if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
- return true;
- }
- }
- return false;
- }
-
- };
-
- var PolygonMixin = {
-
- getEditorClass: function (tools) {
- return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor;
- },
-
- shapeAt: function (latlng, latlngs) {
- // We can have those cases:
- // - latlngs are just a flat array of latlngs, use this
- // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
- // - latlngs is an array of arrays of arrays, this is a multi, loop over
- var shape = null;
- latlngs = latlngs || this._latlngs;
- if (!latlngs.length) return shape;
- else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
- else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs;
- else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i];
- return shape;
- },
-
- isInLatLngs: function (l, latlngs) {
- var inside = false, l1, l2, j, k, len2;
-
- for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
- l1 = latlngs[j];
- l2 = latlngs[k];
-
- if (((l1.lat > l.lat) !== (l2.lat > l.lat)) &&
- (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) {
- inside = !inside;
- }
- }
-
- return inside;
- },
-
- parentShape: function (shape, latlngs) {
- latlngs = latlngs || this._latlngs;
- if (!latlngs) return;
- var idx = L.Util.indexOf(latlngs, shape);
- if (idx !== -1) return latlngs;
- for (var i = 0; i < latlngs.length; i++) {
- idx = L.Util.indexOf(latlngs[i], shape);
- if (idx !== -1) return latlngs[i];
- }
- }
-
- };
-
-
- var MarkerMixin = {
-
- getEditorClass: function (tools) {
- return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor;
- }
-
- };
-
- var RectangleMixin = {
-
- getEditorClass: function (tools) {
- return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor;
- }
-
- };
-
- var CircleMixin = {
-
- getEditorClass: function (tools) {
- return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor;
- }
-
- };
-
- var keepEditable = function () {
- // Make sure you can remove/readd an editable layer.
- this.on('add', this._onEditableAdd);
- };
-
- var isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat; // <=> 1.1 compat.
-
-
- if (L.Polyline) {
- L.Polyline.include(EditableMixin);
- L.Polyline.include(PolylineMixin);
- L.Polyline.addInitHook(keepEditable);
- }
- if (L.Polygon) {
- L.Polygon.include(EditableMixin);
- L.Polygon.include(PolygonMixin);
- }
- if (L.Marker) {
- L.Marker.include(EditableMixin);
- L.Marker.include(MarkerMixin);
- L.Marker.addInitHook(keepEditable);
- }
- if (L.Rectangle) {
- L.Rectangle.include(EditableMixin);
- L.Rectangle.include(RectangleMixin);
- }
- if (L.Circle) {
- L.Circle.include(EditableMixin);
- L.Circle.include(CircleMixin);
- }
-
- L.LatLng.prototype.update = function (latlng) {
- latlng = L.latLng(latlng);
- this.lat = latlng.lat;
- this.lng = latlng.lng;
- };
-
- }, window));
-} (Leaflet_Editable));
-
-/* A Draggable that does not update the element position
-and takes care of only bubbling to targetted path in Canvas mode. */
-L.PathDraggable = L.Draggable.extend({
-
- initialize: function (path) {
- this._path = path;
- this._canvas = (path._map.getRenderer(path) instanceof L.Canvas);
- var element = this._canvas ? this._path._map.getRenderer(this._path)._container : this._path._path;
- L.Draggable.prototype.initialize.call(this, element, element, true);
- },
-
- _updatePosition: function () {
- var e = {originalEvent: this._lastEvent};
- this.fire('drag', e);
- },
-
- _onDown: function (e) {
- var first = e.touches ? e.touches[0] : e;
- this._startPoint = new L.Point(first.clientX, first.clientY);
- if (this._canvas && !this._path._containsPoint(this._path._map.mouseEventToLayerPoint(first))) { return; }
- L.Draggable.prototype._onDown.call(this, e);
- }
-
-});
-
-
-L.Handler.PathDrag = L.Handler.extend({
-
- initialize: function (path) {
- this._path = path;
- },
-
- getEvents: function () {
- return {
- dragstart: this._onDragStart,
- drag: this._onDrag,
- dragend: this._onDragEnd
- };
- },
-
- addHooks: function () {
- if (!this._draggable) { this._draggable = new L.PathDraggable(this._path); }
- this._draggable.on(this.getEvents(), this).enable();
- L.DomUtil.addClass(this._draggable._element, 'leaflet-path-draggable');
- },
-
- removeHooks: function () {
- this._draggable.off(this.getEvents(), this).disable();
- L.DomUtil.removeClass(this._draggable._element, 'leaflet-path-draggable');
- },
-
- moved: function () {
- return this._draggable && this._draggable._moved;
- },
-
- _onDragStart: function () {
- this._startPoint = this._draggable._startPoint;
- this._path
- .closePopup()
- .fire('movestart')
- .fire('dragstart');
- },
-
- _onDrag: function (e) {
- var path = this._path,
- event = (e.originalEvent.touches && e.originalEvent.touches.length === 1 ? e.originalEvent.touches[0] : e.originalEvent),
- newPoint = L.point(event.clientX, event.clientY),
- latlng = path._map.layerPointToLatLng(newPoint);
-
- this._offset = newPoint.subtract(this._startPoint);
- this._startPoint = newPoint;
-
- this._path.eachLatLng(this.updateLatLng, this);
- path.redraw();
-
- e.latlng = latlng;
- e.offset = this._offset;
- path.fire('move', e)
- .fire('drag', e);
- },
-
- _onDragEnd: function (e) {
- if (this._path._bounds) this.resetBounds();
- this._path.fire('moveend')
- .fire('dragend', e);
- },
-
- latLngToLayerPoint: function (latlng) {
- // Same as map.latLngToLayerPoint, but without the round().
- var projectedPoint = this._path._map.project(L.latLng(latlng));
- return projectedPoint._subtract(this._path._map.getPixelOrigin());
- },
-
- updateLatLng: function (latlng) {
- var oldPoint = this.latLngToLayerPoint(latlng);
- oldPoint._add(this._offset);
- var newLatLng = this._path._map.layerPointToLatLng(oldPoint);
- latlng.lat = newLatLng.lat;
- latlng.lng = newLatLng.lng;
- },
-
- resetBounds: function () {
- this._path._bounds = new L.LatLngBounds();
- this._path.eachLatLng(function (latlng) {
- this._bounds.extend(latlng);
- });
- }
-
-});
-
-L.Path.include({
-
- eachLatLng: function (callback, context) {
- context = context || this;
- var loop = function (latlngs) {
- for (var i = 0; i < latlngs.length; i++) {
- if (L.Util.isArray(latlngs[i])) loop(latlngs[i]);
- else callback.call(context, latlngs[i]);
- }
- };
- loop(this.getLatLngs ? this.getLatLngs() : [this.getLatLng()]);
- }
-
-});
-
-L.Path.addInitHook(function () {
-
- this.dragging = new L.Handler.PathDrag(this);
- if (this.options.draggable) {
- this.once('add', function () {
- this.dragging.enable();
- });
- }
-
-});
-
class AddAnother {
connect() {
$("[data-action='add-another']").on("click", function(event) {
@@ -7229,10 +3672,6 @@ const Spotlight$1 = function() {
window.Spotlight = Spotlight$1;
window.SirTrevor = SirTrevor;
-Blacklight.onLoad(function() {
- Spotlight$1.activate();
-});
-
class Crop {
constructor(cropArea) {
this.cropArea = cropArea;
@@ -10200,9 +6639,6 @@ SirTrevor.Locales.en.blocks = $.extend(SirTrevor.Locales.en.blocks, {
}
});
-// These scripts are in the vendor directory
-
-
class AdminIndex {
connect() {
new AddAnother().connect();
diff --git a/app/assets/javascripts/spotlight/spotlight.esm.js.map b/app/assets/javascripts/spotlight/spotlight.esm.js.map
index 268e9843d..75b0e6257 100644
--- a/app/assets/javascripts/spotlight/spotlight.esm.js.map
+++ b/app/assets/javascripts/spotlight/spotlight.esm.js.map
@@ -1 +1 @@
-{"version":3,"file":"spotlight.esm.js","sources":["../../../../vendor/assets/javascripts/tiny-slider.js","../../../javascript/spotlight/user/browse_group_categories.js","../../../javascript/spotlight/user/carousel.js","../../../javascript/spotlight/user/clear_form_button.js","../../../javascript/spotlight/user/report_a_problem.js","../../../javascript/spotlight/user/zpr_links.js","../../../javascript/spotlight/user/index.js","../../../../vendor/assets/javascripts/nestable.js","../../../../vendor/assets/javascripts/bootstrap-tagsinput.js","../../../../vendor/assets/javascripts/typeahead.bundle.min.js","../../../../vendor/assets/javascripts/leaflet-iiif.js","../../../../vendor/assets/javascripts/Leaflet.Editable.js","../../../../vendor/assets/javascripts/Path.Drag.js","../../../javascript/spotlight/admin/add_another.js","../../../javascript/spotlight/admin/add_new_button.js","../../../javascript/spotlight/admin/blacklight_configuration.js","../../../javascript/spotlight/admin/copy_email_addresses.js","../../../javascript/spotlight/admin/iiif.js","../../../javascript/spotlight/admin/add_image_selector.js","../../../javascript/spotlight/core.js","../../../javascript/spotlight/admin/crop.js","../../../javascript/spotlight/admin/croppable.js","../../../javascript/spotlight/admin/edit_in_place.js","../../../javascript/spotlight/admin/exhibit_tag_autocomplete.js","../../../../vendor/assets/javascripts/parameterize.js","../../../javascript/spotlight/admin/exhibits.js","../../../javascript/spotlight/admin/form_observer.js","../../../javascript/spotlight/admin/locks.js","../../../javascript/spotlight/admin/multi_image_selector.js","../../../javascript/spotlight/admin/pages.js","../../../javascript/spotlight/admin/progress_monitor.js","../../../javascript/spotlight/admin/readonly_checkbox.js","../../../javascript/spotlight/admin/search_typeahead.js","../../../javascript/spotlight/admin/select_related_input.js","../../../javascript/spotlight/admin/spotlight_nestable.js","../../../javascript/spotlight/admin/tabs.js","../../../javascript/spotlight/admin/translation_progress.js","../../../javascript/spotlight/admin/visibility_toggle.js","../../../javascript/spotlight/admin/users.js","../../../javascript/spotlight/admin/block_mixins/autocompleteable.js","../../../javascript/spotlight/admin/block_mixins/formable.js","../../../javascript/spotlight/admin/block_mixins/plustextable.js","../../../javascript/spotlight/admin/blocks/block.js","../../../javascript/spotlight/admin/blocks/resources_block.js","../../../javascript/spotlight/admin/blocks/browse_block.js","../../../javascript/spotlight/admin/blocks/browse_group_categories_block.js","../../../javascript/spotlight/admin/blocks/iframe_block.js","../../../javascript/spotlight/admin/blocks/link_to_search_block.js","../../../javascript/spotlight/admin/blocks/oembed_block.js","../../../javascript/spotlight/admin/blocks/pages_block.js","../../../javascript/spotlight/admin/blocks/rule_block.js","../../../javascript/spotlight/admin/blocks/search_result_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_base_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_carousel_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_embed_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_features_block.js","../../../javascript/spotlight/admin/blocks/solr_documents_grid_block.js","../../../javascript/spotlight/admin/blocks/uploaded_items_block.js","../../../javascript/spotlight/admin/sir-trevor/block_controls.js","../../../javascript/spotlight/admin/sir-trevor/block_limits.js","../../../javascript/spotlight/admin/sir-trevor/locales.js","../../../javascript/spotlight/admin/index.js","../../../javascript/spotlight/index.js"],"sourcesContent":["// Includes an unreleased RTL support pull request: https://github.com/ganlanyuan/tiny-slider/pull/658\n// Includes \"export default tns\" at the end of the file for spotlight/user/browse_group_categories.js\nvar tns = (function (){\nvar win = window;\n\nvar raf = win.requestAnimationFrame\n || win.webkitRequestAnimationFrame\n || win.mozRequestAnimationFrame\n || win.msRequestAnimationFrame\n || function(cb) { return setTimeout(cb, 16); };\n\nvar win$1 = window;\n\nvar caf = win$1.cancelAnimationFrame\n || win$1.mozCancelAnimationFrame\n || function(id){ clearTimeout(id); };\n\nfunction extend() {\n var obj, name, copy,\n target = arguments[0] || {},\n i = 1,\n length = arguments.length;\n\n for (; i < length; i++) {\n if ((obj = arguments[i]) !== null) {\n for (name in obj) {\n copy = obj[name];\n\n if (target === copy) {\n continue;\n } else if (copy !== undefined) {\n target[name] = copy;\n }\n }\n }\n }\n return target;\n}\n\nfunction checkStorageValue (value) {\n return ['true', 'false'].indexOf(value) >= 0 ? JSON.parse(value) : value;\n}\n\nfunction setLocalStorage(storage, key, value, access) {\n if (access) {\n try { storage.setItem(key, value); } catch (e) {}\n }\n return value;\n}\n\nfunction getSlideId() {\n var id = window.tnsId;\n window.tnsId = !id ? 1 : id + 1;\n \n return 'tns' + window.tnsId;\n}\n\nfunction getBody () {\n var doc = document,\n body = doc.body;\n\n if (!body) {\n body = doc.createElement('body');\n body.fake = true;\n }\n\n return body;\n}\n\nvar docElement = document.documentElement;\n\nfunction setFakeBody (body) {\n var docOverflow = '';\n if (body.fake) {\n docOverflow = docElement.style.overflow;\n //avoid crashing IE8, if background image is used\n body.style.background = '';\n //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible\n body.style.overflow = docElement.style.overflow = 'hidden';\n docElement.appendChild(body);\n }\n\n return docOverflow;\n}\n\nfunction resetFakeBody (body, docOverflow) {\n if (body.fake) {\n body.remove();\n docElement.style.overflow = docOverflow;\n // Trigger layout so kinetic scrolling isn't disabled in iOS6+\n // eslint-disable-next-line\n docElement.offsetHeight;\n }\n}\n\n// get css-calc \n\nfunction calc() {\n var doc = document, \n body = getBody(),\n docOverflow = setFakeBody(body),\n div = doc.createElement('div'), \n result = false;\n\n body.appendChild(div);\n try {\n var str = '(10px * 10)',\n vals = ['calc' + str, '-moz-calc' + str, '-webkit-calc' + str],\n val;\n for (var i = 0; i < 3; i++) {\n val = vals[i];\n div.style.width = val;\n if (div.offsetWidth === 100) { \n result = val.replace(str, ''); \n break;\n }\n }\n } catch (e) {}\n \n body.fake ? resetFakeBody(body, docOverflow) : div.remove();\n\n return result;\n}\n\n// get subpixel support value\n\nfunction percentageLayout() {\n // check subpixel layout supporting\n var doc = document,\n body = getBody(),\n docOverflow = setFakeBody(body),\n wrapper = doc.createElement('div'),\n outer = doc.createElement('div'),\n str = '',\n count = 70,\n perPage = 3,\n supported = false;\n\n wrapper.className = \"tns-t-subp2\";\n outer.className = \"tns-t-ct\";\n\n for (var i = 0; i < count; i++) {\n str += '';\n }\n\n outer.innerHTML = str;\n wrapper.appendChild(outer);\n body.appendChild(wrapper);\n\n supported = Math.abs(wrapper.getBoundingClientRect().left - outer.children[count - perPage].getBoundingClientRect().left) < 2;\n\n body.fake ? resetFakeBody(body, docOverflow) : wrapper.remove();\n\n return supported;\n}\n\nfunction mediaquerySupport () {\n if (window.matchMedia || window.msMatchMedia) {\n return true;\n }\n \n var doc = document,\n body = getBody(),\n docOverflow = setFakeBody(body),\n div = doc.createElement('div'),\n style = doc.createElement('style'),\n rule = '@media all and (min-width:1px){.tns-mq-test{position:absolute}}',\n position;\n\n style.type = 'text/css';\n div.className = 'tns-mq-test';\n\n body.appendChild(style);\n body.appendChild(div);\n\n if (style.styleSheet) {\n style.styleSheet.cssText = rule;\n } else {\n style.appendChild(doc.createTextNode(rule));\n }\n\n position = window.getComputedStyle ? window.getComputedStyle(div).position : div.currentStyle['position'];\n\n body.fake ? resetFakeBody(body, docOverflow) : div.remove();\n\n return position === \"absolute\";\n}\n\n// create and append style sheet\nfunction createStyleSheet (media, nonce) {\n // Create the