UNPKG

foam-framework

Version:
222 lines (194 loc) 6.06 kB
/** * @license * Copyright 2014 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ CLASS({ package: 'foam.ui', name: 'AutocompleteView', extends: 'foam.ui.PopupView', help: 'Default autocomplete popup.', requires: [ 'foam.ui.ChoiceListView' ], properties: [ 'closeTimeout', 'autocompleter', 'completer', 'current', { model_: 'IntProperty', name: 'closeTime', units: 'ms', help: 'Time to delay the actual close on a .close call.', defaultValue: 200 }, { name: 'view', postSet: function(prev, v) { if ( prev ) { prev.data$.removeListener(this.complete); prev.choices$.removeListener(this.choicesUpdate); } v.data$.addListener(this.complete); v.choices$.addListener(this.choicesUpdate); } }, { name: 'target', postSet: function(prev, v) { prev && prev.unsubscribe(['keydown'], this.onKeyDown); v.subscribe(['keydown'], this.onKeyDown); } }, { name: 'maxHeight', defaultValue: 400 }, { name: 'className', defaultValue: 'autocompletePopup' } ], methods: { autocomplete: function(partial) { if ( ! this.completer ) { var proto = this.X.lookup(this.autocompleter); this.completer = proto.create(null, this.Y); } if ( ! this.view ) { this.view = this.makeView(); } this.current = partial; this.open(this.target); this.completer.autocomplete(partial); }, makeView: function() { return this.ChoiceListView.create({ dao: this.completer.autocompleteDao$Proxy, extraClassName: 'autocomplete', orientation: 'vertical', mode: 'final', objToChoice: this.completer.f, useSelection: true }, this.Y); }, init: function(args) { this.SUPER(args); this.subscribe('blur', (function() { this.close(); }).bind(this)); }, open: function(e, opt_delay) { if ( this.closeTimeout ) { this.X.clearTimeout(this.closeTimeout); this.closeTimeout = 0; } if ( this.$ ) { this.position(this.$.firstElementChild, e.$ || e); return; } var parentNode = e.$ || e; var document = parentNode.ownerDocument; console.assert( this.X.document === document, 'X.document is not global document'); var div = document.createElement('div'); var window = document.defaultView; console.assert( this.X.window === window, 'X.window is not global window'); parentNode.insertAdjacentHTML('afterend', this.toHTML().trim()); this.position(this.$.firstElementChild, parentNode); this.initHTML(); }, close: function(opt_now) { if ( opt_now ) { if ( this.closeTimeout ) { this.X.clearTimeout(this.closeTimeout); this.closeTimeout = 0; } this.SUPER(); return; } if ( this.closeTimeout ) return; var realClose = this.SUPER; var self = this; this.closeTimeout = this.X.setTimeout(function() { self.closeTimeout = 0; realClose.call(self); }, this.closeTime); }, position: function(div, parentNode) { var document = parentNode.ownerDocument; var pos = findPageXY(parentNode); var pageWH = [document.firstElementChild.offsetWidth, document.firstElementChild.offsetHeight]; if ( pageWH[1] - (pos[1] + parentNode.offsetHeight) < (this.height || this.maxHeight || 400) ) { div.style.bottom = parentNode.offsetHeight; document.defaultView.innerHeight - pos[1]; } if ( pos[2].offsetWidth - pos[0] < 600 ) div.style.left = 600 - pos[2].offsetWidth; else div.style.left = -parentNode.offsetWidth; if ( this.width ) div.style.width = this.width + 'px'; if ( this.height ) div.style.height = this.height + 'px'; if ( this.maxWidth ) { div.style.maxWidth = this.maxWidth + 'px'; div.style.overflowX = 'auto'; } if ( this.maxHeight ) { div.style.maxHeight = this.maxHeight + 'px'; div.style.overflowY = 'auto'; } } }, listeners: [ { name: 'onKeyDown', code: function(_, __, e) { if ( ! this.view ) return; if ( e.keyCode === 38 /* arrow up */ ) { this.view.index--; this.view.scrollToSelection(this.$); e.preventDefault(); } else if ( e.keyCode === 40 /* arrow down */ ) { this.view.index++; this.view.scrollToSelection(this.$); e.preventDefault(); } else if ( e.keyCode === 13 /* enter */ ) { this.view.commit(); e.preventDefault(); } } }, { name: 'complete', code: function() { this.target.onAutocomplete(this.view.data); this.view = this.makeView(); this.close(true); } }, { name: 'choicesUpdate', code: function() { if ( this.view && ( this.view.choices.length === 0 || ( this.view.choices.length === 1 && this.view.choices[0][1] === this.current ) ) ) { this.close(true); } } } ], templates: [ function toHTML() {/* <span id="<%= this.id %>" style="position:relative"><div <%= this.cssClassAttr() %> style="position:absolute"><%= this.view %></div></span> */} ] });