diff --git a/app/Resources/views/layout.html.twig b/app/Resources/views/layout.html.twig index 458f0ab..45e9ab9 100644 --- a/app/Resources/views/layout.html.twig +++ b/app/Resources/views/layout.html.twig @@ -19,12 +19,8 @@ {% endblock %} {% block head_js %} - {# HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries #} - {# Who uses IE??? #} - + + {% endblock %} @@ -46,8 +42,6 @@ {# Footer JavaScripts for faster loading #} {% block footer_js %} - - {% endblock %} {%- endblock %} diff --git a/app/config/config.yml b/app/config/config.yml index 79e1ae9..cafefe9 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -35,6 +35,9 @@ sensio_framework_extra: # Twig Configuration twig: + form: + resources: + - bootstrap_3_layout.html.twig debug: "%kernel.debug%" strict_variables: "%kernel.debug%" @@ -82,4 +85,4 @@ swiftmailer: knp_markdown: parser: - service: markdown.parser.point \ No newline at end of file + service: markdown.parser.point diff --git a/composer.lock b/composer.lock index 5744533..b8c3905 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,6 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "68f896fc6d55e4454cb5f2d9be639e6f", "content-hash": "15efa608e772ff5c6381daec33cf9114", "packages": [ { @@ -73,7 +72,7 @@ "docblock", "parser" ], - "time": "2015-08-31 12:32:49" + "time": "2015-08-31T12:32:49+00:00" }, { "name": "doctrine/cache", @@ -143,7 +142,7 @@ "cache", "caching" ], - "time": "2015-12-31 16:37:02" + "time": "2015-12-31T16:37:02+00:00" }, { "name": "doctrine/collections", @@ -209,7 +208,7 @@ "collections", "iterator" ], - "time": "2015-04-14 22:21:58" + "time": "2015-04-14T22:21:58+00:00" }, { "name": "doctrine/common", @@ -282,7 +281,7 @@ "persistence", "spl" ], - "time": "2015-12-25 13:18:31" + "time": "2015-12-25T13:18:31+00:00" }, { "name": "doctrine/dbal", @@ -345,7 +344,7 @@ "persistence", "queryobject" ], - "time": "2016-01-05 22:18:20" + "time": "2016-01-05T22:18:20+00:00" }, { "name": "doctrine/doctrine-bundle", @@ -424,7 +423,7 @@ "orm", "persistence" ], - "time": "2016-01-10 17:21:44" + "time": "2016-01-10T17:21:44+00:00" }, { "name": "doctrine/doctrine-cache-bundle", @@ -512,7 +511,7 @@ "cache", "caching" ], - "time": "2016-01-26 17:28:51" + "time": "2016-01-26T17:28:51+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -570,7 +569,7 @@ "migrations", "schema" ], - "time": "2015-11-04 13:45:30" + "time": "2015-11-04T13:45:30+00:00" }, { "name": "doctrine/inflector", @@ -637,7 +636,7 @@ "singularize", "string" ], - "time": "2015-11-06 14:35:42" + "time": "2015-11-06T14:35:42+00:00" }, { "name": "doctrine/instantiator", @@ -691,7 +690,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "doctrine/lexer", @@ -745,7 +744,7 @@ "lexer", "parser" ], - "time": "2014-09-09 13:34:57" + "time": "2014-09-09T13:34:57+00:00" }, { "name": "doctrine/migrations", @@ -818,7 +817,7 @@ "database", "migrations" ], - "time": "2016-03-14 12:29:11" + "time": "2016-03-14T12:29:11+00:00" }, { "name": "doctrine/orm", @@ -891,7 +890,7 @@ "database", "orm" ], - "time": "2015-08-31 13:19:01" + "time": "2015-08-31T13:19:01+00:00" }, { "name": "guzzle/guzzle", @@ -986,7 +985,8 @@ "rest", "web service" ], - "time": "2015-03-18 18:23:50" + "abandoned": "guzzlehttp/guzzle", + "time": "2015-03-18T18:23:50+00:00" }, { "name": "incenteev/composer-parameter-handler", @@ -1037,7 +1037,7 @@ "keywords": [ "parameters management" ], - "time": "2015-06-03 08:27:03" + "time": "2015-06-03T08:27:03+00:00" }, { "name": "jdorn/sql-formatter", @@ -1087,7 +1087,7 @@ "highlight", "sql" ], - "time": "2014-01-12 16:20:24" + "time": "2014-01-12T16:20:24+00:00" }, { "name": "jms/metadata", @@ -1139,7 +1139,7 @@ "xml", "yaml" ], - "time": "2014-07-12 07:13:19" + "time": "2014-07-12T07:13:19+00:00" }, { "name": "jms/parser-lib", @@ -1174,7 +1174,7 @@ "Apache2" ], "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18 18:08:43" + "time": "2012-11-18T18:08:43+00:00" }, { "name": "jms/serializer", @@ -1247,7 +1247,7 @@ "serialization", "xml" ], - "time": "2015-10-27 09:24:41" + "time": "2015-10-27T09:24:41+00:00" }, { "name": "jms/serializer-bundle", @@ -1317,7 +1317,7 @@ "serialization", "xml" ], - "time": "2015-11-10 12:26:42" + "time": "2015-11-10T12:26:42+00:00" }, { "name": "knplabs/knp-markdown-bundle", @@ -1378,7 +1378,7 @@ "knplabs", "markdown" ], - "time": "2015-12-15 20:41:45" + "time": "2015-12-15T20:41:45+00:00" }, { "name": "kriswallsmith/assetic", @@ -1456,7 +1456,7 @@ "compression", "minification" ], - "time": "2015-08-31 19:07:16" + "time": "2015-08-31T19:07:16+00:00" }, { "name": "michelf/php-markdown", @@ -1507,7 +1507,7 @@ "keywords": [ "markdown" ], - "time": "2015-12-24 01:37:31" + "time": "2015-12-24T01:37:31+00:00" }, { "name": "misd/guzzle-bundle", @@ -1579,7 +1579,8 @@ "rest", "web service" ], - "time": "2014-12-01 08:29:51" + "abandoned": true, + "time": "2014-12-01T08:29:51+00:00" }, { "name": "monolog/monolog", @@ -1655,7 +1656,7 @@ "logging", "psr-3" ], - "time": "2015-08-31 09:17:37" + "time": "2015-08-31T09:17:37+00:00" }, { "name": "ob/highcharts-bundle", @@ -1710,7 +1711,7 @@ "marcaube", "ob" ], - "time": "2014-08-04 23:56:54" + "time": "2014-08-04T23:56:54+00:00" }, { "name": "ocramius/proxy-manager", @@ -1773,7 +1774,7 @@ "proxy pattern", "service proxies" ], - "time": "2015-08-09 04:28:19" + "time": "2015-08-09T04:28:19+00:00" }, { "name": "phpcollection/phpcollection", @@ -1823,7 +1824,7 @@ "sequence", "set" ], - "time": "2014-03-11 13:46:42" + "time": "2014-03-11T13:46:42+00:00" }, { "name": "phpoption/phpoption", @@ -1873,7 +1874,7 @@ "php", "type" ], - "time": "2015-07-25 16:39:46" + "time": "2015-07-25T16:39:46+00:00" }, { "name": "psr/log", @@ -1911,7 +1912,7 @@ "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2012-12-21T11:40:51+00:00" }, { "name": "sensio/distribution-bundle", @@ -1971,7 +1972,7 @@ "configuration", "distribution" ], - "time": "2015-08-03 10:07:12" + "time": "2015-08-03T10:07:12+00:00" }, { "name": "sensio/framework-extra-bundle", @@ -2026,7 +2027,7 @@ "annotations", "controllers" ], - "time": "2015-08-03 11:59:27" + "time": "2015-08-03T11:59:27+00:00" }, { "name": "sensiolabs/security-checker", @@ -2070,7 +2071,7 @@ } ], "description": "A security checker for your composer.lock", - "time": "2015-08-11 12:11:25" + "time": "2015-08-11T12:11:25+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -2123,7 +2124,7 @@ "mail", "mailer" ], - "time": "2015-06-06 14:19:39" + "time": "2015-06-06T14:19:39+00:00" }, { "name": "symfony/assetic-bundle", @@ -2193,7 +2194,7 @@ "compression", "minification" ], - "time": "2015-09-01 00:05:29" + "time": "2015-09-01T00:05:29+00:00" }, { "name": "symfony/monolog-bundle", @@ -2252,7 +2253,7 @@ "log", "logging" ], - "time": "2015-10-02 11:51:59" + "time": "2015-10-02T11:51:59+00:00" }, { "name": "symfony/swiftmailer-bundle", @@ -2309,7 +2310,7 @@ ], "description": "Symfony SwiftmailerBundle", "homepage": "http://symfony.com", - "time": "2014-12-01 17:44:50" + "time": "2014-12-01T17:44:50+00:00" }, { "name": "symfony/symfony", @@ -2431,7 +2432,7 @@ "keywords": [ "framework" ], - "time": "2015-09-25 11:16:52" + "time": "2015-09-25T11:16:52+00:00" }, { "name": "twig/extensions", @@ -2483,7 +2484,7 @@ "i18n", "text" ], - "time": "2015-08-22 16:38:35" + "time": "2015-08-22T16:38:35+00:00" }, { "name": "twig/twig", @@ -2544,7 +2545,7 @@ "keywords": [ "templating" ], - "time": "2015-09-22 13:59:32" + "time": "2015-09-22T13:59:32+00:00" }, { "name": "zendframework/zend-code", @@ -2596,7 +2597,7 @@ "code", "zf2" ], - "time": "2016-01-05 05:58:37" + "time": "2016-01-05T05:58:37+00:00" }, { "name": "zendframework/zend-eventmanager", @@ -2650,7 +2651,7 @@ "events", "zf2" ], - "time": "2016-02-18 20:53:00" + "time": "2016-02-18T20:53:00+00:00" }, { "name": "zendframework/zend-json", @@ -2704,7 +2705,7 @@ "json", "zf2" ], - "time": "2014-03-12 16:10:15" + "time": "2014-03-12T16:10:15+00:00" }, { "name": "zendframework/zend-stdlib", @@ -2759,7 +2760,7 @@ "stdlib", "zf2" ], - "time": "2014-03-12 16:10:15" + "time": "2014-03-12T16:10:15+00:00" } ], "packages-dev": [ @@ -2818,7 +2819,7 @@ "keywords": [ "database" ], - "time": "2015-03-30 12:14:13" + "time": "2015-03-30T12:14:13+00:00" }, { "name": "doctrine/doctrine-fixtures-bundle", @@ -2875,7 +2876,7 @@ "Fixture", "persistence" ], - "time": "2015-11-04 21:23:23" + "time": "2015-11-04T21:23:23+00:00" }, { "name": "sensio/generator-bundle", @@ -2923,7 +2924,7 @@ } ], "description": "This bundle generates code for you", - "time": "2015-03-17 06:36:52" + "time": "2015-03-17T06:36:52+00:00" } ], "aliases": [], diff --git a/src/Skobkin/Bundle/PointToolsBundle/Controller/MainController.php b/src/Skobkin/Bundle/PointToolsBundle/Controller/MainController.php index f6a3d34..ed4e72f 100644 --- a/src/Skobkin/Bundle/PointToolsBundle/Controller/MainController.php +++ b/src/Skobkin/Bundle/PointToolsBundle/Controller/MainController.php @@ -3,17 +3,42 @@ namespace Skobkin\Bundle\PointToolsBundle\Controller; use Doctrine\ORM\EntityManager; -use Doctrine\ORM\QueryBuilder; +use Skobkin\Bundle\PointToolsBundle\Form\UserSearchType; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\Form\FormError; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; class MainController extends Controller { - public function indexAction() + public function indexAction(Request $request) { /** @var EntityManager $em */ $em = $this->getDoctrine()->getManager(); + $form = $this->createForm( + new UserSearchType(), + null, + [ + 'action' => $this->generateUrl('index'), + 'method' => 'POST', + ] + ); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $login = $form->get('login')->getData(); + + if (null !== $user = $em->getRepository('SkobkinPointToolsBundle:User')->findOneBy(['login' => $login])) { + return $this->redirectToRoute('user_show', ['login' => $login]); + } + + $form->get('login')->addError(new FormError('Login not found')); + } + return $this->render('SkobkinPointToolsBundle:Main:index.html.twig', [ + 'form' => $form->createView(), 'users_count' => $em->getRepository('SkobkinPointToolsBundle:User')->getUsersCount(), 'subscribers_count' => $em->getRepository('SkobkinPointToolsBundle:Subscription')->getUserSubscribersCountById($this->container->getParameter('point_id')), 'events_count' => $em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastDayEventsCount(), @@ -21,4 +46,20 @@ class MainController extends Controller 'last_events' => $em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastSubscriptionEvents(10), ]); } + + public function searchUserAjaxAction($login) + { + $em = $this->getDoctrine()->getManager(); + + $result = []; + + foreach ($em->getRepository('SkobkinPointToolsBundle:User')->findUsersLikeLogin($login) as $user) { + $result[] = [ + 'login' => $user->getLogin(), + 'name' => $user->getName(), + ]; + } + + return new JsonResponse($result); + } } diff --git a/src/Skobkin/Bundle/PointToolsBundle/Controller/UserController.php b/src/Skobkin/Bundle/PointToolsBundle/Controller/UserController.php index e328161..b1af69b 100644 --- a/src/Skobkin/Bundle/PointToolsBundle/Controller/UserController.php +++ b/src/Skobkin/Bundle/PointToolsBundle/Controller/UserController.php @@ -50,19 +50,6 @@ class UserController extends Controller ]); } - /** - * @param Request $request - */ - public function searchUserAction(Request $request) - { - $login = $request->request->get('login'); - - if (!$login) { - return $this->redirectToRoute('index'); - } - return $this->redirectToRoute('user_show', ['login' => $login]); - } - /** * @param TopUserDTO[] $topUsers * @return Highchart diff --git a/src/Skobkin/Bundle/PointToolsBundle/Form/UserSearchType.php b/src/Skobkin/Bundle/PointToolsBundle/Form/UserSearchType.php new file mode 100644 index 0000000..48b6871 --- /dev/null +++ b/src/Skobkin/Bundle/PointToolsBundle/Form/UserSearchType.php @@ -0,0 +1,39 @@ +add('login') + ; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Skobkin\Bundle\PointToolsBundle\Entity\User', + ]); + } + + /** + * @return string + */ + public function getName() + { + return 'skobkin_bundle_pointtoolsbundle_user_search'; + } +} diff --git a/src/Skobkin/Bundle/PointToolsBundle/Repository/UserRepository.php b/src/Skobkin/Bundle/PointToolsBundle/Repository/UserRepository.php index 2565fff..ba1bed4 100644 --- a/src/Skobkin/Bundle/PointToolsBundle/Repository/UserRepository.php +++ b/src/Skobkin/Bundle/PointToolsBundle/Repository/UserRepository.php @@ -12,7 +12,7 @@ class UserRepository extends EntityRepository * Case-insensitive user search * * @param string $login - * @return User[] + * @return User|null * @throws \Doctrine\ORM\NonUniqueResultException */ public function findUserByLogin($login) @@ -28,6 +28,31 @@ class UserRepository extends EntityRepository ; } + /** + * Case insensitive user LIKE %login% search + * + * @param string $login + * + * @return User[] + */ + public function findUsersLikeLogin($login) + { + if (empty($login)) { + return []; + } + + $qb = $this->createQueryBuilder('u'); + + return $qb + ->where('u.login LIKE :login') + ->orderBy('u.login', 'ASC') + ->setMaxResults(10) + ->setParameter('login', '%'.strtolower($login).'%') + ->getQuery() + ->getResult() + ; + } + /** * @return integer */ diff --git a/src/Skobkin/Bundle/PointToolsBundle/Resources/config/routing.yml b/src/Skobkin/Bundle/PointToolsBundle/Resources/config/routing.yml index a5c24e8..74cd91d 100644 --- a/src/Skobkin/Bundle/PointToolsBundle/Resources/config/routing.yml +++ b/src/Skobkin/Bundle/PointToolsBundle/Resources/config/routing.yml @@ -2,10 +2,12 @@ index: path: / defaults: { _controller: SkobkinPointToolsBundle:Main:index } -user_search: - path: /user/search - defaults: { _controller: SkobkinPointToolsBundle:User:searchUser } - methods: [POST] +user_search_ajax: + path: /ajax/users/search/{login} + defaults: { _controller: SkobkinPointToolsBundle:Main:searchUserAjax, _format: json } + requirements: + login: "[\w-]*" + _format: json user_show: path: /user/{login} diff --git a/src/Skobkin/Bundle/PointToolsBundle/Resources/views/Main/index.html.twig b/src/Skobkin/Bundle/PointToolsBundle/Resources/views/Main/index.html.twig index 5274662..95b922f 100644 --- a/src/Skobkin/Bundle/PointToolsBundle/Resources/views/Main/index.html.twig +++ b/src/Skobkin/Bundle/PointToolsBundle/Resources/views/Main/index.html.twig @@ -1,18 +1,52 @@ {% extends "::base.html.twig" %} +{% block head_js %} + {{ parent() }} + +{% endblock %} + {% block content %}
- {# @todo rewrite to Symfony forms #} -
+ {{ form_start(form, {'attr': {'class': 'form-inline'} }) }}
- -
-
@
- -
+ {{ form_errors(form.login) }} + {{ form_widget(form.login, {'attr': {'autocomplete': 'off'}}) }} + + + +
- -
+ {{ form_end(form) }}
diff --git a/web/app_dev.php b/web/app_dev.php index 5879870..f8b866d 100644 --- a/web/app_dev.php +++ b/web/app_dev.php @@ -11,7 +11,7 @@ umask(0002); // Feel free to remove this, extend it, or make something more sophisticated. if (isset($_SERVER['HTTP_CLIENT_IP']) || isset($_SERVER['HTTP_X_FORWARDED_FOR']) - || !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1', '192.168.1.2', '192.168.1.14')) || php_sapi_name() === 'cli-server') + || !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server') ) { header('HTTP/1.0 403 Forbidden'); exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); diff --git a/web/js/bootstrap3-typeahead.min.js b/web/js/bootstrap3-typeahead.min.js new file mode 100644 index 0000000..93d4c92 --- /dev/null +++ b/web/js/bootstrap3-typeahead.min.js @@ -0,0 +1 @@ +(function(root,factory){"use strict";if(typeof module!=="undefined"&&module.exports){module.exports=factory(require("jquery"))}else if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else{factory(root.jQuery)}})(this,function($){"use strict";var Typeahead=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.typeahead.defaults,options);this.matcher=this.options.matcher||this.matcher;this.sorter=this.options.sorter||this.sorter;this.select=this.options.select||this.select;this.autoSelect=typeof this.options.autoSelect=="boolean"?this.options.autoSelect:true;this.highlighter=this.options.highlighter||this.highlighter;this.render=this.options.render||this.render;this.updater=this.options.updater||this.updater;this.displayText=this.options.displayText||this.displayText;this.source=this.options.source;this.delay=this.options.delay;this.$menu=$(this.options.menu);this.$appendTo=this.options.appendTo?$(this.options.appendTo):null;this.fitToElement=typeof this.options.fitToElement=="boolean"?this.options.fitToElement:false;this.shown=false;this.listen();this.showHintOnFocus=typeof this.options.showHintOnFocus=="boolean"||this.options.showHintOnFocus==="all"?this.options.showHintOnFocus:false;this.afterSelect=this.options.afterSelect;this.addItem=false;this.value=this.$element.val()||this.$element.text()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").data("value");this.$element.data("active",val);if(this.autoSelect||val){var newVal=this.updater(val);if(!newVal){newVal=""}this.$element.val(this.displayText(newVal)||newVal).text(this.displayText(newVal)||newVal).change();this.afterSelect(newVal)}return this.hide()},updater:function(item){return item},setSource:function(source){this.source=source},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});var scrollHeight=typeof this.options.scrollHeight=="function"?this.options.scrollHeight.call():this.options.scrollHeight;var element;if(this.shown){element=this.$menu}else if(this.$appendTo){element=this.$menu.appendTo(this.$appendTo);this.hasSameParent=this.$appendTo.is(this.$element.parent())}else{element=this.$menu.insertAfter(this.$element);this.hasSameParent=true}if(!this.hasSameParent){element.css("position","fixed");var offset=this.$element.offset();pos.top=offset.top;pos.left=offset.left}var dropup=$(element).parent().hasClass("dropup");var newTop=dropup?"auto":pos.top+pos.height+scrollHeight;var right=$(element).hasClass("dropdown-menu-right");var newLeft=right?"auto":pos.left;element.css({top:newTop,left:newLeft}).show();if(this.options.fitToElement===true){element.css("width",this.$element.outerWidth()+"px")}this.shown=true;return this},hide:function(){this.$menu.hide();this.shown=false;return this},lookup:function(query){var items;if(typeof query!="undefined"&&query!==null){this.query=query}else{this.query=this.$element.val()||this.$element.text()||""}if(this.query.length0){this.$element.data("active",items[0])}else{this.$element.data("active",null)}if(this.options.addItem){items.push(this.options.addItem)}if(this.options.items=="all"){return this.render(items).show()}else{return this.render(items.slice(0,this.options.items)).show()}},matcher:function(item){var it=this.displayText(item);return~it.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(items){var beginswith=[];var caseSensitive=[];var caseInsensitive=[];var item;while(item=items.shift()){var it=this.displayText(item);if(!it.toLowerCase().indexOf(this.query.toLowerCase()))beginswith.push(item);else if(~it.indexOf(this.query))caseSensitive.push(item);else caseInsensitive.push(item)}return beginswith.concat(caseSensitive,caseInsensitive)},highlighter:function(item){var html=$("
");var query=this.query;var i=item.toLowerCase().indexOf(query.toLowerCase());var len=query.length;var leftPart;var middlePart;var rightPart;var strong;if(len===0){return html.text(item).html()}while(i>-1){leftPart=item.substr(0,i);middlePart=item.substr(i,len);rightPart=item.substr(i+len);strong=$("").text(middlePart);html.append(document.createTextNode(leftPart)).append(strong);item=rightPart;i=item.toLowerCase().indexOf(query.toLowerCase())}return html.append(document.createTextNode(item)).html()},render:function(items){var that=this;var self=this;var activeFound=false;var data=[];var _category=that.options.separator;$.each(items,function(key,value){if(key>0&&value[_category]!==items[key-1][_category]){data.push({__type:"divider"})}if(value[_category]&&(key===0||value[_category]!==items[key-1][_category])){data.push({__type:"category",name:value[_category]})}data.push(value)});items=$(data).map(function(i,item){if((item.__type||false)=="category"){return $(that.options.headerHtml).text(item.name)[0]}if((item.__type||false)=="divider"){return $(that.options.headerDivider)[0]}var text=self.displayText(item);i=$(that.options.item).data("value",item);i.find("a").html(that.highlighter(text,item));if(text==self.$element.val()){i.addClass("active");self.$element.data("active",item);activeFound=true}return i[0]});if(this.autoSelect&&!activeFound){items.filter(":not(.dropdown-header)").first().addClass("active");this.$element.data("active",items.first().data("value"))}this.$menu.html(items);return this},displayText:function(item){return typeof item!=="undefined"&&typeof item.name!="undefined"&&item.name||item},next:function(event){var active=this.$menu.find(".active").removeClass("active");var next=active.next();if(!next.length){next=$(this.$menu.find("li")[0])}next.addClass("active")},prev:function(event){var active=this.$menu.find(".active").removeClass("active");var prev=active.prev();if(!prev.length){prev=this.$menu.find("li").last()}prev.addClass("active")},listen:function(){this.$element.on("focus",$.proxy(this.focus,this)).on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("input",$.proxy(this.input,this)).on("keyup",$.proxy(this.keyup,this));if(this.eventSupported("keydown")){this.$element.on("keydown",$.proxy(this.keydown,this))}this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this)).on("mouseleave","li",$.proxy(this.mouseleave,this)).on("mousedown",$.proxy(this.mousedown,this))},destroy:function(){this.$element.data("typeahead",null);this.$element.data("active",null);this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup");if(this.eventSupported("keydown")){this.$element.off("keydown")}this.$menu.remove();this.destroyed=true},eventSupported:function(eventName){var isSupported=eventName in this.$element;if(!isSupported){this.$element.setAttribute(eventName,"return;");isSupported=typeof this.$element[eventName]==="function"}return isSupported},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:if(e.shiftKey)return;e.preventDefault();this.prev();break;case 40:if(e.shiftKey)return;e.preventDefault();this.next();break}},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]);if(!this.shown&&e.keyCode==40){this.lookup()}else{this.move(e)}},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},input:function(e){var currentValue=this.$element.val()||this.$element.text();if(this.value!==currentValue){this.value=currentValue;this.lookup()}},keyup:function(e){if(this.destroyed){return}switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break}},focus:function(e){if(!this.focused){this.focused=true;if(this.options.showHintOnFocus&&this.skipShowHintOnFocus!==true){if(this.options.showHintOnFocus==="all"){this.lookup("")}else{this.lookup()}}}if(this.skipShowHintOnFocus){this.skipShowHintOnFocus=false}},blur:function(e){if(!this.mousedover&&!this.mouseddown&&this.shown){this.hide();this.focused=false}else if(this.mouseddown){this.skipShowHintOnFocus=true;this.$element.focus();this.mouseddown=false}},click:function(e){e.preventDefault();this.skipShowHintOnFocus=true;this.select();this.$element.focus();this.hide()},mouseenter:function(e){this.mousedover=true;this.$menu.find(".active").removeClass("active");$(e.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=false;if(!this.focused&&this.shown)this.hide()},mousedown:function(e){this.mouseddown=true;this.$menu.one("mouseup",function(e){this.mouseddown=false}.bind(this))}};var old=$.fn.typeahead;$.fn.typeahead=function(option){var arg=arguments;if(typeof option=="string"&&option=="getActive"){return this.data("active")}return this.each(function(){var $this=$(this);var data=$this.data("typeahead");var options=typeof option=="object"&&option;if(!data)$this.data("typeahead",data=new Typeahead(this,options));if(typeof option=="string"&&data[option]){if(arg.length>1){data[option].apply(data,Array.prototype.slice.call(arg,1))}else{data[option]()}}})};$.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1,scrollHeight:0,autoSelect:true,afterSelect:$.noop,addItem:false,delay:0,separator:"category",headerHtml:'',headerDivider:''};$.fn.typeahead.Constructor=Typeahead;$.fn.typeahead.noConflict=function(){$.fn.typeahead=old;return this};$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);if($this.data("typeahead"))return;$this.typeahead($this.data())})});