mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
uses angular autocomplete modules
This commit is contained in:
@@ -120,17 +120,11 @@ block content
|
||||
div(ng-show="formVisable")
|
||||
form(enctype='multipart/form-data', method='post')
|
||||
.input
|
||||
input(type='text', name='first_name', ng-model="userInfoForm.first_name", ng-blur="sendUpdate()")
|
||||
input(type='text', name='first_name', ng-model="userInfoForm.first_name", ng-blur="sendUpdate()", placeholder="First Name")
|
||||
.input
|
||||
input(type='text', name='last_name', ng-model="userInfoForm.last_name", ng-blur="sendUpdate()", placeholder='Last Name')
|
||||
.input
|
||||
input(type='text', name='institution', ng-model="userInfoForm.institution", placeholder='Institution', ng-blur="sendUpdate()", ng-keyup="updateInstitutionsList()", list="_institutions")
|
||||
datalist#_institutions
|
||||
option(ng-repeat='institution in institutions') {{institution.name}}
|
||||
|
||||
|
||||
|
||||
|
||||
.input#institution_auto_complete
|
||||
autocomplete(ng-model="userInfoForm.institution", data="institutions", on-type="updateInstitutionsList", attr-placeholder="Institution")
|
||||
.input
|
||||
input(type='text', name='role', ng-model="userInfoForm.role", placeholder='Role', ng-blur="sendUpdate()")
|
||||
.span3
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
define ["libs/algolia", "libs/typeahead", "libs/angular"], (algolia)->
|
||||
define ["libs/algolia", "libs/angular", "libs/angular-autocomplete/angular-autocomplete"], (algolia)->
|
||||
|
||||
app = angular.module("userProfileInformationApp", [])
|
||||
app = angular.module("userProfileInformationApp", ["autocomplete"])
|
||||
|
||||
app.factory "Institutions", ->
|
||||
new AlgoliaSearch("SK53GL4JLY", "75dc5e65794cd47eb7f725e6bb5075be").initIndex("institutions")
|
||||
|
||||
app.controller "UpdateForm", ($scope, $http, Institutions)->
|
||||
$scope.institutions =
|
||||
$scope.institutions = []
|
||||
$scope.hidePersonalInfoSection = true
|
||||
|
||||
$http.get("/user/personal_info").success (data)->
|
||||
@@ -33,9 +33,9 @@ define ["libs/algolia", "libs/typeahead", "libs/angular"], (algolia)->
|
||||
results = _.filter $scope.userInfoForm, (value)-> value? and value?.length != 0
|
||||
results.length * 20
|
||||
|
||||
$scope.updateInstitutionsList = ->
|
||||
$scope.updateInstitutionsList = (a)->
|
||||
Institutions.search $scope.userInfoForm.institution, (err, response)->
|
||||
$scope.institutions = response.hits
|
||||
$scope.institutions = _.pluck response.hits, "name"
|
||||
|
||||
angular.bootstrap(document.getElementById("userProfileInformation"), ['userProfileInformationApp'])
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="autocomplete {{ attrs.class }}" id="{{ attrs.id }}">
|
||||
<input
|
||||
type="text"
|
||||
ng-model="searchParam"
|
||||
placeholder="{{ attrs.placeholder }}"
|
||||
class="{{ attrs.inputclass }}"
|
||||
id="{{ attrs.inputid }}"/>
|
||||
<ul ng-show="completing">
|
||||
<li
|
||||
suggestion
|
||||
ng-repeat="suggestion in suggestions | filter:searchFilter | orderBy:'toString()' track by $index"
|
||||
index="{{ $index }}"
|
||||
val="{{ suggestion }}"
|
||||
ng-class="{ active: ($index === selectedIndex) }"
|
||||
ng-click="select(suggestion)"
|
||||
ng-bind-html="suggestion | highlight:searchParam"></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,265 @@
|
||||
/* --- Made by justgoscha and licensed under MIT license --- */
|
||||
|
||||
define(["libs/angular"], function(){
|
||||
|
||||
|
||||
|
||||
var app = angular.module('autocomplete', []);
|
||||
|
||||
app.directive('autocomplete', function() {
|
||||
var index = -1;
|
||||
console.log("helllo")
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
searchParam: '=ngModel',
|
||||
suggestions: '=data',
|
||||
onType: '=onType',
|
||||
onSelect: '=onSelect'
|
||||
},
|
||||
controller: ['$scope', function($scope){
|
||||
// the index of the suggestions that's currently selected
|
||||
$scope.selectedIndex = -1;
|
||||
|
||||
// set new index
|
||||
$scope.setIndex = function(i){
|
||||
$scope.selectedIndex = parseInt(i);
|
||||
};
|
||||
|
||||
this.setIndex = function(i){
|
||||
$scope.setIndex(i);
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
$scope.getIndex = function(i){
|
||||
return $scope.selectedIndex;
|
||||
};
|
||||
|
||||
// watches if the parameter filter should be changed
|
||||
var watching = true;
|
||||
|
||||
// autocompleting drop down on/off
|
||||
$scope.completing = false;
|
||||
|
||||
// starts autocompleting on typing in something
|
||||
$scope.$watch('searchParam', function(newValue, oldValue){
|
||||
if (oldValue === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(watching && $scope.searchParam) {
|
||||
$scope.completing = true;
|
||||
$scope.searchFilter = $scope.searchParam;
|
||||
$scope.selectedIndex = -1;
|
||||
}
|
||||
|
||||
// function thats passed to on-type attribute gets executed
|
||||
if($scope.onType)
|
||||
$scope.onType($scope.searchParam);
|
||||
});
|
||||
|
||||
// for hovering over suggestions
|
||||
this.preSelect = function(suggestion){
|
||||
|
||||
watching = false;
|
||||
|
||||
// this line determines if it is shown
|
||||
// in the input field before it's selected:
|
||||
//$scope.searchParam = suggestion;
|
||||
|
||||
$scope.$apply();
|
||||
watching = true;
|
||||
|
||||
};
|
||||
|
||||
$scope.preSelect = this.preSelect;
|
||||
|
||||
this.preSelectOff = function(){
|
||||
watching = true;
|
||||
};
|
||||
|
||||
$scope.preSelectOff = this.preSelectOff;
|
||||
|
||||
// selecting a suggestion with RIGHT ARROW or ENTER
|
||||
$scope.select = function(suggestion){
|
||||
if(suggestion){
|
||||
$scope.searchParam = suggestion;
|
||||
$scope.searchFilter = suggestion;
|
||||
if($scope.onSelect)
|
||||
$scope.onSelect(suggestion);
|
||||
}
|
||||
watching = false;
|
||||
$scope.completing = false;
|
||||
setTimeout(function(){watching = true;},1000);
|
||||
$scope.setIndex(-1);
|
||||
};
|
||||
|
||||
|
||||
}],
|
||||
link: function(scope, element, attrs){
|
||||
|
||||
var attr = '';
|
||||
|
||||
// Default atts
|
||||
scope.attrs = {
|
||||
"placeholder": "start typing...",
|
||||
"class": "",
|
||||
"id": "",
|
||||
"inputclass": "",
|
||||
"inputid": ""
|
||||
};
|
||||
|
||||
for (var a in attrs) {
|
||||
attr = a.replace('attr', '').toLowerCase();
|
||||
// add attribute overriding defaults
|
||||
// and preventing duplication
|
||||
if (a.indexOf('attr') === 0) {
|
||||
scope.attrs[attr] = attrs[a];
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs.clickActivation) {
|
||||
element[0].onclick = function(e){
|
||||
if(!scope.searchParam){
|
||||
scope.completing = true;
|
||||
scope.$apply();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var key = {left: 37, up: 38, right: 39, down: 40 , enter: 13, esc: 27};
|
||||
|
||||
document.addEventListener("keydown", function(e){
|
||||
var keycode = e.keyCode || e.which;
|
||||
|
||||
switch (keycode){
|
||||
case key.esc:
|
||||
// disable suggestions on escape
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
e.preventDefault();
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.addEventListener("blur", function(e){
|
||||
// disable suggestions on blur
|
||||
// we do a timeout to prevent hiding it before a click event is registered
|
||||
setTimeout(function() {
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
}, 200);
|
||||
}, true);
|
||||
|
||||
element[0].addEventListener("keydown",function (e){
|
||||
var keycode = e.keyCode || e.which;
|
||||
|
||||
var l = angular.element(this).find('li').length;
|
||||
|
||||
// implementation of the up and down movement in the list of suggestions
|
||||
switch (keycode){
|
||||
case key.up:
|
||||
|
||||
index = scope.getIndex()-1;
|
||||
if(index<-1){
|
||||
index = l-1;
|
||||
} else if (index >= l ){
|
||||
index = -1;
|
||||
scope.setIndex(index);
|
||||
scope.preSelectOff();
|
||||
break;
|
||||
}
|
||||
scope.setIndex(index);
|
||||
|
||||
if(index!==-1)
|
||||
scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
|
||||
|
||||
scope.$apply();
|
||||
|
||||
break;
|
||||
case key.down:
|
||||
index = scope.getIndex()+1;
|
||||
if(index<-1){
|
||||
index = l-1;
|
||||
} else if (index >= l ){
|
||||
index = -1;
|
||||
scope.setIndex(index);
|
||||
scope.preSelectOff();
|
||||
scope.$apply();
|
||||
break;
|
||||
}
|
||||
scope.setIndex(index);
|
||||
|
||||
if(index!==-1)
|
||||
scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
|
||||
|
||||
break;
|
||||
case key.left:
|
||||
break;
|
||||
case key.right:
|
||||
case key.enter:
|
||||
|
||||
index = scope.getIndex();
|
||||
// scope.preSelectOff();
|
||||
if(index !== -1)
|
||||
scope.select(angular.element(angular.element(this).find('li')[index]).text());
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
|
||||
break;
|
||||
case key.esc:
|
||||
// disable suggestions on escape
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if(scope.getIndex()!==-1 || keycode == key.enter)
|
||||
e.preventDefault();
|
||||
});
|
||||
},
|
||||
templateUrl: 'js/libs/angular-autocomplete/ac_template.html'
|
||||
};
|
||||
});
|
||||
|
||||
app.filter('highlight', ['$sce', function ($sce) {
|
||||
return function (input, searchParam) {
|
||||
if (typeof input === 'function') return '';
|
||||
if (searchParam) {
|
||||
var words = '(' +
|
||||
searchParam.split(/\ /).join(' |') + '|' +
|
||||
searchParam.split(/\ /).join('|') +
|
||||
')',
|
||||
exp = new RegExp(words, 'gi');
|
||||
if (words.length) {
|
||||
input = input.replace(exp, "<span class=\"highlight\">$1</span>");
|
||||
}
|
||||
}
|
||||
return $sce.trustAsHtml(input);
|
||||
};
|
||||
}]);
|
||||
|
||||
app.directive('suggestion', function(){
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '^autocomplete', // ^look for controller on parents element
|
||||
link: function(scope, element, attrs, autoCtrl){
|
||||
element.bind('mouseenter', function() {
|
||||
autoCtrl.preSelect(attrs.val);
|
||||
autoCtrl.setIndex(attrs.index);
|
||||
});
|
||||
|
||||
element.bind('mouseleave', function() {
|
||||
autoCtrl.preSelectOff();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
})
|
||||
+21675
File diff suppressed because it is too large
Load Diff
@@ -257,6 +257,57 @@ a.archived-projects {
|
||||
color:#626264;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
#completeUserProfileInformation {
|
||||
form {
|
||||
margin:0px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* AUTOCOMPLETE */
|
||||
|
||||
#institution_auto_complete {
|
||||
|
||||
ul>li{
|
||||
list-style:none;
|
||||
}
|
||||
|
||||
.autocomplete{
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.autocomplete ul{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
min-width: 220px;
|
||||
border-left: 1px solid #888;
|
||||
border-right: 1px solid #888;
|
||||
border-bottom: 1px solid #888;
|
||||
z-index: 1;
|
||||
margin: -9px -1px 0px 0px;
|
||||
|
||||
}
|
||||
|
||||
.autocomplete li{
|
||||
text-align: left;
|
||||
list-style:none;
|
||||
padding:0.4em;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.autocomplete li.active{
|
||||
background-color: #BDE1F6;
|
||||
}
|
||||
|
||||
.autocomplete .highlight {
|
||||
background-color: #E2E2E2;
|
||||
}
|
||||
|
||||
.autocomplete li.active .highlight {
|
||||
background: #666;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user