$1<\/strong>')
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/<(\/?strong)>/g, '<$1>');
- };
-
- function _formatGroup(suggestion, category) {
- return '' + category + '
';
- };
-
- Autocomplete.prototype = {
-
- initialize: function () {
- var that = this,
- suggestionSelector = '.' + that.classes.suggestion,
- selected = that.classes.selected,
- options = that.options,
- container;
-
- // Remove autocomplete attribute to prevent native suggestions:
- that.element.setAttribute('autocomplete', 'off');
-
- // html() deals with many types: htmlString or Element or Array or jQuery
- that.noSuggestionsContainer = $('')
- .html(this.options.noSuggestionNotice).get(0);
-
- that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
-
- container = $(that.suggestionsContainer);
-
- container.appendTo(options.appendTo || 'body');
-
- // Only set width if it was provided:
- if (options.width !== 'auto') {
- container.css('width', options.width);
- }
-
- // Listen for mouse over event on suggestions list:
- container.on('mouseover.autocomplete', suggestionSelector, function () {
- that.activate($(this).data('index'));
- });
-
- // Deselect active element when mouse leaves suggestions container:
- container.on('mouseout.autocomplete', function () {
- that.selectedIndex = -1;
- container.children('.' + selected).removeClass(selected);
- });
-
-
- // Listen for click event on suggestions list:
- container.on('click.autocomplete', suggestionSelector, function () {
- that.select($(this).data('index'));
- });
-
- container.on('click.autocomplete', function () {
- clearTimeout(that.blurTimeoutId);
- })
-
- that.fixPositionCapture = function () {
- if (that.visible) {
- that.fixPosition();
- }
- };
-
- $(window).on('resize.autocomplete', that.fixPositionCapture);
-
- that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); });
- that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); });
- that.el.on('blur.autocomplete', function () { that.onBlur(); });
- that.el.on('focus.autocomplete', function () { that.onFocus(); });
- that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); });
- that.el.on('input.autocomplete', function (e) { that.onKeyUp(e); });
- },
-
- onFocus: function () {
- var that = this;
-
- that.fixPosition();
-
- if (that.el.val().length >= that.options.minChars) {
- that.onValueChange();
- }
- },
-
- onBlur: function () {
- var that = this;
-
- // If user clicked on a suggestion, hide() will
- // be canceled, otherwise close suggestions
- that.blurTimeoutId = setTimeout(function () {
- that.hide();
- }, 200);
- },
-
- abortAjax: function () {
- var that = this;
- if (that.currentRequest) {
- that.currentRequest.abort();
- that.currentRequest = null;
- }
- },
-
- setOptions: function (suppliedOptions) {
- var that = this,
- options = that.options;
-
- this.options = $.extend({}, options, suppliedOptions);
-
- that.isLocal = Array.isArray(options.lookup);
-
- if (that.isLocal) {
- options.lookup = that.verifySuggestionsFormat(options.lookup);
- }
-
- options.orientation = that.validateOrientation(options.orientation, 'bottom');
-
- // Adjust height, width and z-index:
- $(that.suggestionsContainer).css({
- 'max-height': options.maxHeight + 'px',
- 'width': options.width + 'px',
- 'z-index': options.zIndex
- });
- },
-
-
- clearCache: function () {
- this.cachedResponse = {};
- this.badQueries = [];
- },
-
- clear: function () {
- this.clearCache();
- this.currentValue = '';
- this.suggestions = [];
- },
-
- disable: function () {
- var that = this;
- that.disabled = true;
- clearTimeout(that.onChangeTimeout);
- that.abortAjax();
- },
-
- enable: function () {
- this.disabled = false;
- },
-
- fixPosition: function () {
- // Use only when container has already its content
-
- var that = this,
- $container = $(that.suggestionsContainer),
- containerParent = $container.parent().get(0);
- // Fix position automatically when appended to body.
- // In other cases force parameter must be given.
- if (containerParent !== document.body && !that.options.forceFixPosition) {
- return;
- }
-
- // Choose orientation
- var orientation = that.options.orientation,
- containerHeight = $container.outerHeight(),
- height = that.el.outerHeight(),
- offset = that.el.offset(),
- styles = { 'top': offset.top, 'left': offset.left };
-
- if (orientation === 'auto') {
- var viewPortHeight = $(window).height(),
- scrollTop = $(window).scrollTop(),
- topOverflow = -scrollTop + offset.top - containerHeight,
- bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
-
- orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) ? 'top' : 'bottom';
- }
-
- if (orientation === 'top') {
- styles.top += -containerHeight;
- } else {
- styles.top += height;
- }
-
- // If container is not positioned to body,
- // correct its position using offset parent offset
- if(containerParent !== document.body) {
- var opacity = $container.css('opacity'),
- parentOffsetDiff;
-
- if (!that.visible){
- $container.css('opacity', 0).show();
- }
-
- parentOffsetDiff = $container.offsetParent().offset();
- styles.top -= parentOffsetDiff.top;
- styles.left -= parentOffsetDiff.left;
-
- if (!that.visible){
- $container.css('opacity', opacity).hide();
- }
- }
-
- if (that.options.width === 'auto') {
- styles.width = that.el.outerWidth() + 'px';
- }
-
- $container.css(styles);
- },
-
- isCursorAtEnd: function () {
- var that = this,
- valLength = that.el.val().length,
- selectionStart = that.element.selectionStart,
- range;
-
- if (typeof selectionStart === 'number') {
- return selectionStart === valLength;
- }
- if (document.selection) {
- range = document.selection.createRange();
- range.moveStart('character', -valLength);
- return valLength === range.text.length;
- }
- return true;
- },
-
- onKeyPress: function (e) {
- var that = this;
-
- // If suggestions are hidden and user presses arrow down, display suggestions:
- if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) {
- that.suggest();
- return;
- }
-
- if (that.disabled || !that.visible) {
- return;
- }
-
- switch (e.which) {
- case keys.ESC:
- that.el.val(that.currentValue);
- that.hide();
- break;
- case keys.RIGHT:
- if (that.hint && that.options.onHint && that.isCursorAtEnd()) {
- that.selectHint();
- break;
- }
- return;
- case keys.TAB:
- if (that.hint && that.options.onHint) {
- that.selectHint();
- return;
- }
- if (that.selectedIndex === -1) {
- that.hide();
- return;
- }
- that.select(that.selectedIndex);
- if (that.options.tabDisabled === false) {
- return;
- }
- break;
- case keys.RETURN:
- if (that.selectedIndex === -1) {
- that.hide();
- return;
- }
- that.select(that.selectedIndex);
- break;
- case keys.UP:
- that.moveUp();
- break;
- case keys.DOWN:
- that.moveDown();
- break;
- default:
- return;
- }
-
- // Cancel event if function did not return:
- e.stopImmediatePropagation();
- e.preventDefault();
- },
-
- onKeyUp: function (e) {
- var that = this;
-
- if (that.disabled) {
- return;
- }
-
- switch (e.which) {
- case keys.UP:
- case keys.DOWN:
- return;
- }
-
- clearTimeout(that.onChangeTimeout);
-
- if (that.currentValue !== that.el.val()) {
- that.findBestHint();
- if (that.options.deferRequestBy > 0) {
- // Defer lookup in case when value changes very quickly:
- that.onChangeTimeout = setTimeout(function () {
- that.onValueChange();
- }, that.options.deferRequestBy);
- } else {
- that.onValueChange();
- }
- }
- },
-
- onValueChange: function () {
- var that = this,
- options = that.options,
- value = that.el.val(),
- query = that.getQuery(value);
-
- if (that.selection && that.currentValue !== query) {
- that.selection = null;
- (options.onInvalidateSelection || $.noop).call(that.element);
- }
-
- clearTimeout(that.onChangeTimeout);
- that.currentValue = value;
- that.selectedIndex = -1;
-
- // Check existing suggestion for the match before proceeding:
- if (options.triggerSelectOnValidInput && that.isExactMatch(query)) {
- that.select(0);
- return;
- }
-
- if (query.length < options.minChars) {
- that.hide();
- } else {
- that.getSuggestions(query);
- }
- },
-
- isExactMatch: function (query) {
- var suggestions = this.suggestions;
-
- return (suggestions.length === 1 && suggestions[0].value.toLowerCase() === query.toLowerCase());
- },
-
- getQuery: function (value) {
- var delimiter = this.options.delimiter,
- parts;
-
- if (!delimiter) {
- return value;
- }
- parts = value.split(delimiter);
- return $.trim(parts[parts.length - 1]);
- },
-
- getSuggestionsLocal: function (query) {
- var that = this,
- options = that.options,
- queryLowerCase = query.toLowerCase(),
- filter = options.lookupFilter,
- limit = parseInt(options.lookupLimit, 10),
- data;
-
- data = {
- suggestions: $.grep(options.lookup, function (suggestion) {
- return filter(suggestion, query, queryLowerCase);
- })
- };
-
- if (limit && data.suggestions.length > limit) {
- data.suggestions = data.suggestions.slice(0, limit);
- }
-
- return data;
- },
-
- getSuggestions: function (q) {
- var response,
- that = this,
- options = that.options,
- serviceUrl = options.serviceUrl,
- params,
- cacheKey,
- ajaxSettings;
-
- options.params[options.paramName] = q;
-
- if (options.onSearchStart.call(that.element, options.params) === false) {
- return;
- }
-
- params = options.ignoreParams ? null : options.params;
-
- if ($.isFunction(options.lookup)){
- options.lookup(q, function (data) {
- that.suggestions = data.suggestions;
- that.suggest();
- options.onSearchComplete.call(that.element, q, data.suggestions);
- });
- return;
- }
-
- if (that.isLocal) {
- response = that.getSuggestionsLocal(q);
- } else {
- if ($.isFunction(serviceUrl)) {
- serviceUrl = serviceUrl.call(that.element, q);
- }
- cacheKey = serviceUrl + '?' + $.param(params || {});
- response = that.cachedResponse[cacheKey];
- }
-
- if (response && Array.isArray(response.suggestions)) {
- that.suggestions = response.suggestions;
- that.suggest();
- options.onSearchComplete.call(that.element, q, response.suggestions);
- } else if (!that.isBadQuery(q)) {
- that.abortAjax();
-
- ajaxSettings = {
- url: serviceUrl,
- data: params,
- type: options.type,
- dataType: options.dataType
- };
-
- $.extend(ajaxSettings, options.ajaxSettings);
-
- that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
- var result;
- that.currentRequest = null;
- result = options.transformResult(data, q);
- that.processResponse(result, q, cacheKey);
- options.onSearchComplete.call(that.element, q, result.suggestions);
- }).fail(function (jqXHR, textStatus, errorThrown) {
- options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
- });
- } else {
- options.onSearchComplete.call(that.element, q, []);
- }
- },
-
- isBadQuery: function (q) {
- if (!this.options.preventBadQueries){
- return false;
- }
-
- var badQueries = this.badQueries,
- i = badQueries.length;
-
- while (i--) {
- if (q.indexOf(badQueries[i]) === 0) {
- return true;
- }
- }
-
- return false;
- },
-
- hide: function () {
- var that = this,
- container = $(that.suggestionsContainer);
-
- if ($.isFunction(that.options.onHide) && that.visible) {
- that.options.onHide.call(that.element, container);
- }
-
- that.visible = false;
- that.selectedIndex = -1;
- clearTimeout(that.onChangeTimeout);
- $(that.suggestionsContainer).hide();
- that.signalHint(null);
- },
-
- suggest: function () {
- if (!this.suggestions.length) {
- if (this.options.showNoSuggestionNotice) {
- this.noSuggestions();
- } else {
- this.hide();
- }
- return;
- }
-
- var that = this,
- options = that.options,
- groupBy = options.groupBy,
- formatResult = options.formatResult,
- value = that.getQuery(that.currentValue),
- className = that.classes.suggestion,
- classSelected = that.classes.selected,
- container = $(that.suggestionsContainer),
- noSuggestionsContainer = $(that.noSuggestionsContainer),
- beforeRender = options.beforeRender,
- html = '',
- category,
- formatGroup = function (suggestion, index) {
- var currentCategory = suggestion.data[groupBy];
-
- if (category === currentCategory){
- return '';
- }
-
- category = currentCategory;
-
- return options.formatGroup(suggestion, category);
- };
-
- if (options.triggerSelectOnValidInput && that.isExactMatch(value)) {
- that.select(0);
- return;
- }
-
- // Build suggestions inner HTML:
- $.each(that.suggestions, function (i, suggestion) {
- if (groupBy){
- html += formatGroup(suggestion, value, i);
- }
-
- html += '' + formatResult(suggestion, value, i) + '
';
- });
-
- this.adjustContainerWidth();
-
- noSuggestionsContainer.detach();
- container.html(html);
-
- if ($.isFunction(beforeRender)) {
- beforeRender.call(that.element, container, that.suggestions);
- }
-
- that.fixPosition();
- container.show();
-
- // Select first value by default:
- if (options.autoSelectFirst) {
- that.selectedIndex = 0;
- container.scrollTop(0);
- container.children('.' + className).first().addClass(classSelected);
- }
-
- that.visible = true;
- that.findBestHint();
- },
-
- noSuggestions: function() {
- var that = this,
- beforeRender = that.options.beforeRender,
- container = $(that.suggestionsContainer),
- noSuggestionsContainer = $(that.noSuggestionsContainer);
-
- this.adjustContainerWidth();
-
- // Some explicit steps. Be careful here as it easy to get
- // noSuggestionsContainer removed from DOM if not detached properly.
- noSuggestionsContainer.detach();
-
- // clean suggestions if any
- container.empty();
- container.append(noSuggestionsContainer);
-
- if ($.isFunction(beforeRender)) {
- beforeRender.call(that.element, container, that.suggestions);
- }
-
- that.fixPosition();
-
- container.show();
- that.visible = true;
- },
-
- adjustContainerWidth: function() {
- var that = this,
- options = that.options,
- width,
- container = $(that.suggestionsContainer);
-
- // If width is auto, adjust width before displaying suggestions,
- // because if instance was created before input had width, it will be zero.
- // Also it adjusts if input width has changed.
- if (options.width === 'auto') {
- width = that.el.outerWidth();
- container.css('width', width > 0 ? width : 300);
- } else if(options.width === 'flex') {
- // Trust the source! Unset the width property so it will be the max length
- // the containing elements.
- container.css('width', '');
- }
- },
-
- findBestHint: function () {
- var that = this,
- value = that.el.val().toLowerCase(),
- bestMatch = null;
-
- if (!value) {
- return;
- }
-
- $.each(that.suggestions, function (i, suggestion) {
- var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0;
- if (foundMatch) {
- bestMatch = suggestion;
- }
- return !foundMatch;
- });
-
- that.signalHint(bestMatch);
- },
-
- signalHint: function (suggestion) {
- var hintValue = '',
- that = this;
- if (suggestion) {
- hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length);
- }
- if (that.hintValue !== hintValue) {
- that.hintValue = hintValue;
- that.hint = suggestion;
- (this.options.onHint || $.noop)(hintValue);
- }
- },
-
- verifySuggestionsFormat: function (suggestions) {
- // If suggestions is string array, convert them to supported format:
- if (suggestions.length && typeof suggestions[0] === 'string') {
- return $.map(suggestions, function (value) {
- return { value: value, data: null };
- });
- }
-
- return suggestions;
- },
-
- validateOrientation: function(orientation, fallback) {
- orientation = $.trim(orientation || '').toLowerCase();
-
- if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){
- orientation = fallback;
- }
-
- return orientation;
- },
-
- processResponse: function (result, originalQuery, cacheKey) {
- var that = this,
- options = that.options;
-
- result.suggestions = that.verifySuggestionsFormat(result.suggestions);
-
- // Cache results if cache is not disabled:
- if (!options.noCache) {
- that.cachedResponse[cacheKey] = result;
- if (options.preventBadQueries && !result.suggestions.length) {
- that.badQueries.push(originalQuery);
- }
- }
-
- // Return if originalQuery is not matching current query:
- if (originalQuery !== that.getQuery(that.currentValue)) {
- return;
- }
-
- that.suggestions = result.suggestions;
- that.suggest();
- },
-
- activate: function (index) {
- var that = this,
- activeItem,
- selected = that.classes.selected,
- container = $(that.suggestionsContainer),
- children = container.find('.' + that.classes.suggestion);
-
- container.find('.' + selected).removeClass(selected);
-
- that.selectedIndex = index;
-
- if (that.selectedIndex !== -1 && children.length > that.selectedIndex) {
- activeItem = children.get(that.selectedIndex);
- $(activeItem).addClass(selected);
- return activeItem;
- }
-
- return null;
- },
-
- selectHint: function () {
- var that = this,
- i = $.inArray(that.hint, that.suggestions);
-
- that.select(i);
- },
-
- select: function (i) {
- var that = this;
- that.hide();
- that.onSelect(i);
- },
-
- moveUp: function () {
- var that = this;
-
- if (that.selectedIndex === -1) {
- return;
- }
-
- if (that.selectedIndex === 0) {
- $(that.suggestionsContainer).children().first().removeClass(that.classes.selected);
- that.selectedIndex = -1;
- that.el.val(that.currentValue);
- that.findBestHint();
- return;
- }
-
- that.adjustScroll(that.selectedIndex - 1);
- },
-
- moveDown: function () {
- var that = this;
-
- if (that.selectedIndex === (that.suggestions.length - 1)) {
- return;
- }
-
- that.adjustScroll(that.selectedIndex + 1);
- },
-
- adjustScroll: function (index) {
- var that = this,
- activeItem = that.activate(index);
-
- if (!activeItem) {
- return;
- }
-
- var offsetTop,
- upperBound,
- lowerBound,
- heightDelta = $(activeItem).outerHeight();
-
- offsetTop = activeItem.offsetTop;
- upperBound = $(that.suggestionsContainer).scrollTop();
- lowerBound = upperBound + that.options.maxHeight - heightDelta;
-
- if (offsetTop < upperBound) {
- $(that.suggestionsContainer).scrollTop(offsetTop);
- } else if (offsetTop > lowerBound) {
- $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta);
- }
-
- if (!that.options.preserveInput) {
- that.el.val(that.getValue(that.suggestions[index].value));
- }
- that.signalHint(null);
- },
-
- onSelect: function (index) {
- var that = this,
- onSelectCallback = that.options.onSelect,
- suggestion = that.suggestions[index];
-
- that.currentValue = that.getValue(suggestion.value);
-
- if (that.currentValue !== that.el.val() && !that.options.preserveInput) {
- that.el.val(that.currentValue);
- }
-
- that.signalHint(null);
- that.suggestions = [];
- that.selection = suggestion;
-
- if ($.isFunction(onSelectCallback)) {
- onSelectCallback.call(that.element, suggestion);
- }
- },
-
- getValue: function (value) {
- var that = this,
- delimiter = that.options.delimiter,
- currentValue,
- parts;
-
- if (!delimiter) {
- return value;
- }
-
- currentValue = that.currentValue;
- parts = currentValue.split(delimiter);
-
- if (parts.length === 1) {
- return value;
- }
-
- return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value;
- },
-
- dispose: function () {
- var that = this;
- that.el.off('.autocomplete').removeData('autocomplete');
- $(window).off('resize.autocomplete', that.fixPositionCapture);
- $(that.suggestionsContainer).remove();
- }
- };
-
- // Create chainable jQuery plugin:
- $.fn.devbridgeAutocomplete = function (options, args) {
- var dataKey = 'autocomplete';
- // If function invoked without argument return
- // instance of the first matched element:
- if (!arguments.length) {
- return this.first().data(dataKey);
- }
-
- return this.each(function () {
- var inputElement = $(this),
- instance = inputElement.data(dataKey);
-
- if (typeof options === 'string') {
- if (instance && typeof instance[options] === 'function') {
- instance[options](args);
- }
- } else {
- // If instance already exists, destroy it:
- if (instance && instance.dispose) {
- instance.dispose();
- }
- instance = new Autocomplete(this, options);
- inputElement.data(dataKey, instance);
- }
- });
- };
-
- // Don't overwrite if it already exists
- if (!$.fn.autocomplete) {
- $.fn.autocomplete = $.fn.devbridgeAutocomplete;
- }
-}));
diff --git a/browser/js/lib/jquery.caret.js b/browser/js/lib/jquery.caret.js
new file mode 100644
index 0000000000000000000000000000000000000000..811ec63ee47bb5c71b244c8491820df47015371b
--- /dev/null
+++ b/browser/js/lib/jquery.caret.js
@@ -0,0 +1,436 @@
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(["jquery"], function ($) {
+ return (root.returnExportsGlobal = factory($));
+ });
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like enviroments that support module.exports,
+ // like Node.
+ module.exports = factory(require("jquery"));
+ } else {
+ factory(jQuery);
+ }
+}(this, function ($) {
+
+/*
+ Implement Github like autocomplete mentions
+ http://ichord.github.com/At.js
+
+ Copyright (c) 2013 chord.luo@gmail.com
+ Licensed under the MIT license.
+*/
+
+/*
+本插件操作 textarea 或者 input 内的插入符
+只实现了获得插入符在文本框中的位置,我设置
+插入符的位置.
+*/
+
+"use strict";
+var EditableCaret, InputCaret, Mirror, Utils, discoveryIframeOf, methods, oDocument, oFrame, oWindow, pluginName, setContextBy;
+
+pluginName = 'caret';
+
+EditableCaret = (function() {
+ function EditableCaret($inputor) {
+ this.$inputor = $inputor;
+ this.domInputor = this.$inputor[0];
+ }
+
+ EditableCaret.prototype.setPos = function(pos) {
+ var fn, found, offset, sel;
+ if (sel = oWindow.getSelection()) {
+ offset = 0;
+ found = false;
+ (fn = function(pos, parent) {
+ var node, range, _i, _len, _ref, _results;
+ _ref = parent.childNodes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ node = _ref[_i];
+ if (found) {
+ break;
+ }
+ if (node.nodeType === 3) {
+ if (offset + node.length >= pos) {
+ found = true;
+ range = oDocument.createRange();
+ range.setStart(node, pos - offset);
+ sel.removeAllRanges();
+ sel.addRange(range);
+ break;
+ } else {
+ _results.push(offset += node.length);
+ }
+ } else {
+ _results.push(fn(pos, node));
+ }
+ }
+ return _results;
+ })(pos, this.domInputor);
+ }
+ return this.domInputor;
+ };
+
+ EditableCaret.prototype.getIEPosition = function() {
+ return this.getPosition();
+ };
+
+ EditableCaret.prototype.getPosition = function() {
+ var inputor_offset, offset;
+ offset = this.getOffset();
+ inputor_offset = this.$inputor.offset();
+ offset.left -= inputor_offset.left;
+ offset.top -= inputor_offset.top;
+ return offset;
+ };
+
+ EditableCaret.prototype.getOldIEPos = function() {
+ var preCaretTextRange, textRange;
+ textRange = oDocument.selection.createRange();
+ preCaretTextRange = oDocument.body.createTextRange();
+ preCaretTextRange.moveToElementText(this.domInputor);
+ preCaretTextRange.setEndPoint("EndToEnd", textRange);
+ return preCaretTextRange.text.length;
+ };
+
+ EditableCaret.prototype.getPos = function() {
+ var clonedRange, pos, range;
+ if (range = this.range()) {
+ clonedRange = range.cloneRange();
+ clonedRange.selectNodeContents(this.domInputor);
+ clonedRange.setEnd(range.endContainer, range.endOffset);
+ pos = clonedRange.toString().length;
+ clonedRange.detach();
+ return pos;
+ } else if (oDocument.selection) {
+ return this.getOldIEPos();
+ }
+ };
+
+ EditableCaret.prototype.getOldIEOffset = function() {
+ var range, rect;
+ range = oDocument.selection.createRange().duplicate();
+ range.moveStart("character", -1);
+ rect = range.getBoundingClientRect();
+ return {
+ height: rect.bottom - rect.top,
+ left: rect.left,
+ top: rect.top
+ };
+ };
+
+ EditableCaret.prototype.getOffset = function(pos) {
+ var clonedRange, offset, range, rect, shadowCaret;
+ if (oWindow.getSelection && (range = this.range())) {
+ if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) {
+ clonedRange = range.cloneRange();
+ clonedRange.setStart(range.endContainer, range.endOffset - 1);
+ clonedRange.setEnd(range.endContainer, range.endOffset);
+ rect = clonedRange.getBoundingClientRect();
+ offset = {
+ height: rect.height,
+ left: rect.left + rect.width,
+ top: rect.top
+ };
+ clonedRange.detach();
+ }
+ if (!offset || (offset != null ? offset.height : void 0) === 0) {
+ clonedRange = range.cloneRange();
+ shadowCaret = $(oDocument.createTextNode("|"));
+ clonedRange.insertNode(shadowCaret[0]);
+ clonedRange.selectNode(shadowCaret[0]);
+ rect = clonedRange.getBoundingClientRect();
+ offset = {
+ height: rect.height,
+ left: rect.left,
+ top: rect.top
+ };
+ shadowCaret.remove();
+ clonedRange.detach();
+ }
+ } else if (oDocument.selection) {
+ offset = this.getOldIEOffset();
+ }
+ if (offset) {
+ offset.top += $(oWindow).scrollTop();
+ offset.left += $(oWindow).scrollLeft();
+ }
+ return offset;
+ };
+
+ EditableCaret.prototype.range = function() {
+ var sel;
+ if (!oWindow.getSelection) {
+ return;
+ }
+ sel = oWindow.getSelection();
+ if (sel.rangeCount > 0) {
+ return sel.getRangeAt(0);
+ } else {
+ return null;
+ }
+ };
+
+ return EditableCaret;
+
+})();
+
+InputCaret = (function() {
+ function InputCaret($inputor) {
+ this.$inputor = $inputor;
+ this.domInputor = this.$inputor[0];
+ }
+
+ InputCaret.prototype.getIEPos = function() {
+ var endRange, inputor, len, normalizedValue, pos, range, textInputRange;
+ inputor = this.domInputor;
+ range = oDocument.selection.createRange();
+ pos = 0;
+ if (range && range.parentElement() === inputor) {
+ normalizedValue = inputor.value.replace(/\r\n/g, "\n");
+ len = normalizedValue.length;
+ textInputRange = inputor.createTextRange();
+ textInputRange.moveToBookmark(range.getBookmark());
+ endRange = inputor.createTextRange();
+ endRange.collapse(false);
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
+ pos = len;
+ } else {
+ pos = -textInputRange.moveStart("character", -len);
+ }
+ }
+ return pos;
+ };
+
+ InputCaret.prototype.getPos = function() {
+ if (oDocument.selection) {
+ return this.getIEPos();
+ } else {
+ return this.domInputor.selectionStart;
+ }
+ };
+
+ InputCaret.prototype.setPos = function(pos) {
+ var inputor, range;
+ inputor = this.domInputor;
+ if (oDocument.selection) {
+ range = inputor.createTextRange();
+ range.move("character", pos);
+ range.select();
+ } else if (inputor.setSelectionRange) {
+ inputor.setSelectionRange(pos, pos);
+ }
+ return inputor;
+ };
+
+ InputCaret.prototype.getIEOffset = function(pos) {
+ var h, textRange, x, y;
+ textRange = this.domInputor.createTextRange();
+ pos || (pos = this.getPos());
+ textRange.move('character', pos);
+ x = textRange.boundingLeft;
+ y = textRange.boundingTop;
+ h = textRange.boundingHeight;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ InputCaret.prototype.getOffset = function(pos) {
+ var $inputor, offset, position;
+ $inputor = this.$inputor;
+ if (oDocument.selection) {
+ offset = this.getIEOffset(pos);
+ offset.top += $(oWindow).scrollTop() + $inputor.scrollTop();
+ offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft();
+ return offset;
+ } else {
+ offset = $inputor.offset();
+ position = this.getPosition(pos);
+ return offset = {
+ left: offset.left + position.left - $inputor.scrollLeft(),
+ top: offset.top + position.top - $inputor.scrollTop(),
+ height: position.height
+ };
+ }
+ };
+
+ InputCaret.prototype.getPosition = function(pos) {
+ var $inputor, at_rect, end_range, format, html, mirror, start_range;
+ $inputor = this.$inputor;
+ format = function(value) {
+ value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, "
");
+ if (/firefox/i.test(navigator.userAgent)) {
+ value = value.replace(/\s/g, ' ');
+ }
+ return value;
+ };
+ if (pos === void 0) {
+ pos = this.getPos();
+ }
+ start_range = $inputor.val().slice(0, pos);
+ end_range = $inputor.val().slice(pos);
+ html = "" + format(start_range) + "";
+ html += "|";
+ html += "" + format(end_range) + "";
+ mirror = new Mirror($inputor);
+ return at_rect = mirror.create(html).rect();
+ };
+
+ InputCaret.prototype.getIEPosition = function(pos) {
+ var h, inputorOffset, offset, x, y;
+ offset = this.getIEOffset(pos);
+ inputorOffset = this.$inputor.offset();
+ x = offset.left - inputorOffset.left;
+ y = offset.top - inputorOffset.top;
+ h = offset.height;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ return InputCaret;
+
+})();
+
+Mirror = (function() {
+ Mirror.prototype.css_attr = ["borderBottomWidth", "borderLeftWidth", "borderRightWidth", "borderTopStyle", "borderRightStyle", "borderBottomStyle", "borderLeftStyle", "borderTopWidth", "boxSizing", "fontFamily", "fontSize", "fontWeight", "height", "letterSpacing", "lineHeight", "marginBottom", "marginLeft", "marginRight", "marginTop", "outlineWidth", "overflow", "overflowX", "overflowY", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textAlign", "textOverflow", "textTransform", "whiteSpace", "wordBreak", "wordWrap"];
+
+ function Mirror($inputor) {
+ this.$inputor = $inputor;
+ }
+
+ Mirror.prototype.mirrorCss = function() {
+ var css,
+ _this = this;
+ css = {
+ position: 'absolute',
+ left: -9999,
+ top: 0,
+ zIndex: -20000
+ };
+ if (this.$inputor.prop('tagName') === 'TEXTAREA') {
+ this.css_attr.push('width');
+ }
+ $.each(this.css_attr, function(i, p) {
+ return css[p] = _this.$inputor.css(p);
+ });
+ return css;
+ };
+
+ Mirror.prototype.create = function(html) {
+ this.$mirror = $('');
+ this.$mirror.css(this.mirrorCss());
+ this.$mirror.html(html);
+ this.$inputor.after(this.$mirror);
+ return this;
+ };
+
+ Mirror.prototype.rect = function() {
+ var $flag, pos, rect;
+ $flag = this.$mirror.find("#caret");
+ pos = $flag.position();
+ rect = {
+ left: pos.left,
+ top: pos.top,
+ height: $flag.height()
+ };
+ this.$mirror.remove();
+ return rect;
+ };
+
+ return Mirror;
+
+})();
+
+Utils = {
+ contentEditable: function($inputor) {
+ return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true');
+ }
+};
+
+methods = {
+ pos: function(pos) {
+ if (pos || pos === 0) {
+ return this.setPos(pos);
+ } else {
+ return this.getPos();
+ }
+ },
+ position: function(pos) {
+ if (oDocument.selection) {
+ return this.getIEPosition(pos);
+ } else {
+ return this.getPosition(pos);
+ }
+ },
+ offset: function(pos) {
+ var offset;
+ offset = this.getOffset(pos);
+ return offset;
+ }
+};
+
+oDocument = null;
+
+oWindow = null;
+
+oFrame = null;
+
+setContextBy = function(settings) {
+ var iframe;
+ if (iframe = settings != null ? settings.iframe : void 0) {
+ oFrame = iframe;
+ oWindow = iframe.contentWindow;
+ return oDocument = iframe.contentDocument || oWindow.document;
+ } else {
+ oFrame = void 0;
+ oWindow = window;
+ return oDocument = document;
+ }
+};
+
+discoveryIframeOf = function($dom) {
+ var error;
+ oDocument = $dom[0].ownerDocument;
+ oWindow = oDocument.defaultView || oDocument.parentWindow;
+ try {
+ return oFrame = oWindow.frameElement;
+ } catch (_error) {
+ error = _error;
+ }
+};
+
+$.fn.caret = function(method, value, settings) {
+ var caret;
+ if (methods[method]) {
+ if ($.isPlainObject(value)) {
+ setContextBy(value);
+ value = void 0;
+ } else {
+ setContextBy(settings);
+ }
+ caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this);
+ return methods[method].apply(caret, [value]);
+ } else {
+ return $.error("Method " + method + " does not exist on jQuery.caret");
+ }
+};
+
+$.fn.caret.EditableCaret = EditableCaret;
+
+$.fn.caret.InputCaret = InputCaret;
+
+$.fn.caret.Utils = Utils;
+
+$.fn.caret.apis = methods;
+
+
+}));
diff --git a/browser/js/main.js b/browser/js/main.js
index e66a2ebdfebfe407d110e2e36e43138cdf76423b..be69e927ae515da4bd202dfdc97381e2db020b28 100644
--- a/browser/js/main.js
+++ b/browser/js/main.js
@@ -87,6 +87,8 @@ try {
//TODO
initMenu();
+
+ new VidjilAutoComplete(db.db_address + 'tag/auto_complete');
} catch(err) {
this.db.log_error(err)
}
diff --git a/server/web2py/applications/vidjil/controllers/tag.py b/server/web2py/applications/vidjil/controllers/tag.py
index 88007ef8b320e4c30e86c2f2170846d2b47f4050..5131017c91c3d3928ebbf1527e7d4c961d20cf35 100644
--- a/server/web2py/applications/vidjil/controllers/tag.py
+++ b/server/web2py/applications/vidjil/controllers/tag.py
@@ -10,10 +10,7 @@ def auto_complete():
if "group_id" not in request.vars:
return error_message("missing group id")
- if "query" not in request.vars or request.vars["query"][0] != "#":
- tags = []
- else:
- prefix = get_tag_prefix()
- tags = get_tags(db, request.vars["group_id"], request.vars["query"][len(prefix):])
+ prefix = get_tag_prefix()
+ tags = get_tags(db, request.vars["group_id"])
return tags_to_json(tags)
diff --git a/server/web2py/applications/vidjil/modules/tag.py b/server/web2py/applications/vidjil/modules/tag.py
index 477f5815f3599c310a55b58f9fff9d3b5727770b..6cc38b1b7f8d7713d148aaff06139662b53e9254 100644
--- a/server/web2py/applications/vidjil/modules/tag.py
+++ b/server/web2py/applications/vidjil/modules/tag.py
@@ -87,11 +87,9 @@ def register_tags(db, table, record_id, text, group_id, reset=False):
tag_extractor = TagExtractor(tag_prefix, db)
tags = tag_extractor.execute(table, record_id, text, group_id, reset)
-def get_tags(db, group_id, query):
- like = '%s%%' % query
+def get_tags(db, group_id):
return db((db.tag.id == db.group_tag.tag_id) &
- (db.group_tag.group_id == group_id) &
- (db.tag.name.like(like, case_sensitive=False))
+ (db.group_tag.group_id == group_id)
).select(db.tag.ALL)
def tags_to_json(tags):
@@ -100,8 +98,7 @@ def tags_to_json(tags):
for tag in tags:
tag_dict = {}
tag_dict['id'] = tag.id
- tag_dict['value'] = '%s%s' % (prefix, tag.name)
+ tag_dict['name'] = tag.name
tag_list.append(tag_dict)
- suggestions = {'suggestions': tag_list}
- return json.dumps(suggestions)
+ return json.dumps(tag_list)
diff --git a/server/web2py/applications/vidjil/views/patient/add.html b/server/web2py/applications/vidjil/views/patient/add.html
index 2bb96ea08a4fe67ac3e0b15a68f484635da97b82..7c014c361b1db37a086f767753bf5004d013af06 100644
--- a/server/web2py/applications/vidjil/views/patient/add.html
+++ b/server/web2py/applications/vidjil/views/patient/add.html
@@ -32,7 +32,7 @@
|
- |
+ |
|
diff --git a/server/web2py/applications/vidjil/views/patient/edit.html b/server/web2py/applications/vidjil/views/patient/edit.html
index c9d131a1706836c2e783d457296f5d4f4229c757..15b9cea3e12c028c63b694db0278803a64cd8851 100644
--- a/server/web2py/applications/vidjil/views/patient/edit.html
+++ b/server/web2py/applications/vidjil/views/patient/edit.html
@@ -30,7 +30,7 @@ info = db.patient[request.vars["id"]]
|
- |
+ |
|
diff --git a/server/web2py/applications/vidjil/views/run/add.html b/server/web2py/applications/vidjil/views/run/add.html
index b200e02b777e1452320c55fef55c72427be73314..deeda9f992a6bc9e8a11b2a8f4de7a2451056d01 100644
--- a/server/web2py/applications/vidjil/views/run/add.html
+++ b/server/web2py/applications/vidjil/views/run/add.html
@@ -27,7 +27,7 @@
|
- |
+ |
|
diff --git a/server/web2py/applications/vidjil/views/run/edit.html b/server/web2py/applications/vidjil/views/run/edit.html
index 2683a8ec34551282eb7349673f0fc295371f3821..611c95e7ed46f934f0f213b09aaff2505eff3c6b 100644
--- a/server/web2py/applications/vidjil/views/run/edit.html
+++ b/server/web2py/applications/vidjil/views/run/edit.html
@@ -25,7 +25,7 @@ info = db.run[request.vars["id"]]
|
- |
+ |
|
diff --git a/server/web2py/applications/vidjil/views/sample_set/add.html b/server/web2py/applications/vidjil/views/sample_set/add.html
index 1afa4fcd721c5a6f7ffb9e1bb3cef9cfcaca033f..bb0278673db39a91cbc92dedf317e540dd085bf3 100644
--- a/server/web2py/applications/vidjil/views/sample_set/add.html
+++ b/server/web2py/applications/vidjil/views/sample_set/add.html
@@ -17,7 +17,7 @@
|
- |
+ |
|
diff --git a/server/web2py/applications/vidjil/views/sample_set/edit.html b/server/web2py/applications/vidjil/views/sample_set/edit.html
index 6ac55d6ae6dfbff5f89dee37c21f5a201daafc71..9838846bca819f01ba6e083808c3550acf4e3399 100644
--- a/server/web2py/applications/vidjil/views/sample_set/edit.html
+++ b/server/web2py/applications/vidjil/views/sample_set/edit.html
@@ -15,7 +15,7 @@ info = db.generic[request.vars["id"]]
|
- |
+ |
|