Преглед изворни кода

Merge branch 'master' into feature/1359-BonusTravelCarHouse

kevin_zhangl пре 3 година
родитељ
комит
2a89abe20f
100 измењених фајлова са 2617 додато и 12463 уклоњено
  1. 49 49
      backendApi/config/menu.php
  2. 2 0
      backendApi/config/urlManagerRules.php
  3. 1 1
      backendApi/modules/v1/controllers/BonusController.php
  4. 74 2
      backendApi/modules/v1/controllers/ShopController.php
  5. 3 0
      backendApi/modules/v1/controllers/UserController.php
  6. 64 19
      backendApi/modules/v1/models/lists/bonus/BalanceList.php
  7. 220 220
      backendApi/modules/v1/models/lists/bonus/PeriodBonusList.php
  8. 38 1
      backendApi/modules/v1/models/lists/shop/DecOrderList.php
  9. 11 2
      backendApi/modules/v1/models/lists/shop/GoodsList.php
  10. 11 1
      backendEle/src/views/config/period.vue
  11. 43 1
      backendEle/src/views/shop/dec-order-list.vue
  12. 40 20
      backendEle/src/views/shop/goods-add.vue
  13. 54 31
      backendEle/src/views/shop/index.vue
  14. 42 0
      backendEle/src/views/shop/order-list.vue
  15. 13 1
      common/config/params.php
  16. 5 0
      common/helpers/Constant.php
  17. 89 103
      common/helpers/bonus/BonusCalc.php
  18. 38 0
      common/helpers/bonus/BonusSend.php
  19. 30 0
      common/helpers/bonus/CalcCache.php
  20. 100 1
      common/helpers/user/Balance.php
  21. 235 2
      common/libs/export/BaseExport.php
  22. 16 4
      common/models/BalanceAudit.php
  23. 8 2
      common/models/CalcBonus.php
  24. 9 1
      common/models/DealType.php
  25. 81 0
      common/models/FlowZonePoints.php
  26. 6 2
      common/models/OrderGoods.php
  27. 70 9
      common/models/ShopGoods.php
  28. 8 2
      common/models/UserBonus.php
  29. 15 3
      common/models/forms/ConfigPeriodForm.php
  30. 31 20
      common/models/forms/DeclarationForm.php
  31. 115 26
      common/models/forms/OrderForm.php
  32. 41 6
      common/models/forms/ShopGoodsForm.php
  33. 6 2
      composer.json
  34. 48 0
      console/controllers/ShopController.php
  35. 1 1
      frontendApi/config/menu.php
  36. 3 1
      frontendApi/config/urlManagerRules.php
  37. 144 91
      frontendApi/modules/v1/controllers/BonusController.php
  38. 499 8
      frontendApi/modules/v1/controllers/ShopController.php
  39. 4 0
      frontendApi/modules/v1/controllers/UserController.php
  40. 46 17
      frontendEle/src/views/bonus/other.vue
  41. 22 2
      frontendEle/src/views/shop/dec-order-list.vue
  42. 67 36
      frontendEle/src/views/shop/index.vue
  43. 28 5
      frontendEle/src/views/shop/order-list.vue
  44. 158 60
      frontendEle/src/views/shop/order.vue
  45. 5 5
      frontendEle/src/views/shop/reconsume-order.vue
  46. 24 4
      frontendEle/src/views/user/dec.vue
  47. 0 16
      vendor/bower-asset/typeahead.js/.gitignore
  48. 0 16
      vendor/bower-asset/typeahead.js/.jshintrc
  49. 0 29
      vendor/bower-asset/typeahead.js/.travis.yml
  50. 0 249
      vendor/bower-asset/typeahead.js/CHANGELOG.md
  51. 0 120
      vendor/bower-asset/typeahead.js/CONTRIBUTING.md
  52. 0 330
      vendor/bower-asset/typeahead.js/Gruntfile.js
  53. 0 188
      vendor/bower-asset/typeahead.js/README.md
  54. 0 13
      vendor/bower-asset/typeahead.js/bower.json
  55. 0 17
      vendor/bower-asset/typeahead.js/composer.json
  56. 0 918
      vendor/bower-asset/typeahead.js/dist/bloodhound.js
  57. 0 6
      vendor/bower-asset/typeahead.js/dist/bloodhound.min.js
  58. 0 2451
      vendor/bower-asset/typeahead.js/dist/typeahead.bundle.js
  59. 0 6
      vendor/bower-asset/typeahead.js/dist/typeahead.bundle.min.js
  60. 0 1538
      vendor/bower-asset/typeahead.js/dist/typeahead.jquery.js
  61. 0 6
      vendor/bower-asset/typeahead.js/dist/typeahead.jquery.min.js
  62. 0 277
      vendor/bower-asset/typeahead.js/doc/bloodhound.md
  63. 0 288
      vendor/bower-asset/typeahead.js/doc/jquery_typeahead.md
  64. 0 234
      vendor/bower-asset/typeahead.js/doc/migration/0.10.0.md
  65. 0 50
      vendor/bower-asset/typeahead.js/karma.conf.js
  66. 0 68
      vendor/bower-asset/typeahead.js/package.json
  67. 0 192
      vendor/bower-asset/typeahead.js/src/bloodhound/bloodhound.js
  68. 0 101
      vendor/bower-asset/typeahead.js/src/bloodhound/lru_cache.js
  69. 0 195
      vendor/bower-asset/typeahead.js/src/bloodhound/options_parser.js
  70. 0 147
      vendor/bower-asset/typeahead.js/src/bloodhound/persistent_storage.js
  71. 0 91
      vendor/bower-asset/typeahead.js/src/bloodhound/prefetch.js
  72. 0 58
      vendor/bower-asset/typeahead.js/src/bloodhound/remote.js
  73. 0 191
      vendor/bower-asset/typeahead.js/src/bloodhound/search_index.js
  74. 0 44
      vendor/bower-asset/typeahead.js/src/bloodhound/tokenizers.js
  75. 0 130
      vendor/bower-asset/typeahead.js/src/bloodhound/transport.js
  76. 0 7
      vendor/bower-asset/typeahead.js/src/bloodhound/version.js
  77. 0 164
      vendor/bower-asset/typeahead.js/src/common/utils.js
  78. 0 330
      vendor/bower-asset/typeahead.js/src/typeahead/dataset.js
  79. 0 75
      vendor/bower-asset/typeahead.js/src/typeahead/default_menu.js
  80. 0 78
      vendor/bower-asset/typeahead.js/src/typeahead/event_bus.js
  81. 0 119
      vendor/bower-asset/typeahead.js/src/typeahead/event_emitter.js
  82. 0 84
      vendor/bower-asset/typeahead.js/src/typeahead/highlight.js
  83. 0 339
      vendor/bower-asset/typeahead.js/src/typeahead/input.js
  84. 0 217
      vendor/bower-asset/typeahead.js/src/typeahead/menu.js
  85. 0 291
      vendor/bower-asset/typeahead.js/src/typeahead/plugin.js
  86. 0 438
      vendor/bower-asset/typeahead.js/src/typeahead/typeahead.js
  87. 0 113
      vendor/bower-asset/typeahead.js/src/typeahead/www.js
  88. 0 299
      vendor/bower-asset/typeahead.js/test/bloodhound/bloodhound_spec.js
  89. 0 43
      vendor/bower-asset/typeahead.js/test/bloodhound/lru_cache_spec.js
  90. 0 194
      vendor/bower-asset/typeahead.js/test/bloodhound/options_parser_spec.js
  91. 0 194
      vendor/bower-asset/typeahead.js/test/bloodhound/persistent_storage_spec.js
  92. 0 182
      vendor/bower-asset/typeahead.js/test/bloodhound/prefetch_spec.js
  93. 0 73
      vendor/bower-asset/typeahead.js/test/bloodhound/remote_spec.js
  94. 0 72
      vendor/bower-asset/typeahead.js/test/bloodhound/search_index_spec.js
  95. 0 74
      vendor/bower-asset/typeahead.js/test/bloodhound/tokenizers_spec.js
  96. 0 175
      vendor/bower-asset/typeahead.js/test/bloodhound/transport_spec.js
  97. 0 12
      vendor/bower-asset/typeahead.js/test/ci
  98. 0 19
      vendor/bower-asset/typeahead.js/test/fixtures/ajax_responses.js
  99. 0 128
      vendor/bower-asset/typeahead.js/test/fixtures/data.js
  100. 0 13
      vendor/bower-asset/typeahead.js/test/fixtures/html.js

+ 49 - 49
backendApi/config/menu.php

@@ -19,10 +19,10 @@ return [
         'routePath'=>'dashboard/index',
         'show'=>1,
         'child'=>[
-            ['name'=>'总累计', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'total-item', 'routePath'=>'dashboard/total-item', 'show'=>0,],
-            ['name'=>'会员月注册数量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'reg-num', 'routePath'=>'dashboard/reg-num', 'show'=>0,],
-            ['name'=>'月奖金量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'bonus-num', 'routePath'=>'dashboard/bonus-num', 'show'=>0,],
-            ['name'=>'月提现量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'withdraw-num', 'routePath'=>'dashboard/withdraw-num', 'show'=>0,],
+//            ['name'=>'总累计', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'total-item', 'routePath'=>'dashboard/total-item', 'show'=>0,],
+//            ['name'=>'会员月注册数量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'reg-num', 'routePath'=>'dashboard/reg-num', 'show'=>0,],
+//            ['name'=>'月奖金量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'bonus-num', 'routePath'=>'dashboard/bonus-num', 'show'=>0,],
+//            ['name'=>'月提现量', 'class'=>'', 'icon'=>'', 'controller'=>'dashboard', 'action'=>'withdraw-num', 'routePath'=>'dashboard/withdraw-num', 'show'=>0,],
         ]
     ],
     'shop'=>[
@@ -63,14 +63,14 @@ return [
         'child'=>[
             ['name'=>'会员列表', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'index', 'routePath'=>'user/index', 'show'=>1,],
             ['name'=>'登录到前台', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'login-to-frontend', 'routePath'=>'user/login-to-frontend', 'show'=>0,],
-            ['name'=>'指定会员管理登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'batch-close-login', 'routePath'=>'user/batch-close-login', 'show'=>0,],
-            ['name'=>'按条件登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-login', 'routePath'=>'user/close-login', 'show'=>0,],
-            ['name'=>'会员地区登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-area-login', 'routePath'=>'user/close-area-login', 'show'=>0,],
+//            ['name'=>'指定会员管理登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'batch-close-login', 'routePath'=>'user/batch-close-login', 'show'=>0,],
+//            ['name'=>'按条件登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-login', 'routePath'=>'user/close-login', 'show'=>0,],
+//            ['name'=>'会员地区登录管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-area-login', 'routePath'=>'user/close-area-login', 'show'=>0,],
             //['name'=>'会员运作管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-operating', 'routePath'=>'user/is-operating', 'show'=>0,],
 //            ['name'=>'会员团队领导人管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-group', 'routePath'=>'user/is-group', 'show'=>0,],
-            ['name'=>'会员报单中心管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-dec', 'routePath'=>'user/is-dec', 'show'=>0,],
-            ['name'=>'会员工作室管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-studio', 'routePath'=>'user/is-studio', 'show'=>0,],
-            ['name'=>'会员转账比例修改', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'change-transfer-prop', 'routePath'=>'user/change-transfer-prop', 'show'=>0,],
+//            ['name'=>'会员报单中心管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-dec', 'routePath'=>'user/is-dec', 'show'=>0,],
+//            ['name'=>'会员工作室管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'is-studio', 'routePath'=>'user/is-studio', 'show'=>0,],
+//            ['name'=>'会员转账比例修改', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'change-transfer-prop', 'routePath'=>'user/change-transfer-prop', 'show'=>0,],
 //            ['name'=>'指定会员管理报单管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'batch-close-dec', 'routePath'=>'user/batch-close-dec', 'show'=>0,],
 //            ['name'=>'按条件报单管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-dec', 'routePath'=>'user/close-dec', 'show'=>0,],
 //            ['name'=>'会员地区报单管理', 'class'=>'', 'icon'=>'', 'controller'=>'user', 'action'=>'close-area-dec', 'routePath'=>'user/close-area-dec', 'show'=>0,],
@@ -219,42 +219,42 @@ return [
 //            ['name'=>'补发区域津贴审核列表导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'resend-qy-audit-list-export', 'routePath'=>'bonus/resend-qy-audit-list-export', 'show'=>0,],
 //            ['name'=>'补发区域津贴审核操作', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'resend-qy-audit', 'routePath'=>'bonus/resend-qy-audit', 'show'=>0,],
 //            ['name'=>'补发区域津贴审核删除', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'resend-qy-audit-delete', 'routePath'=>'bonus/resend-qy-audit-delete', 'show'=>0,],
-            ['name'=>'团队奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-qy', 'routePath'=>'bonus/trace-down-qy', 'show'=>1,],
-            ['name'=>'团队奖下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-qy-export', 'routePath'=>'bonus/trace-down-qy-export', 'show'=>0,],
-            ['name'=>'团队奖向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-qy', 'routePath'=>'bonus/trace-up-qy', 'show'=>1,],
-            ['name'=>'团队奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-qy-export', 'routePath'=>'bonus/trace-up-qy-export', 'show'=>0,],
-            ['name'=>'荣衔奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yc', 'routePath'=>'bonus/trace-down-yc', 'show'=>1,],
-            ['name'=>'荣衔奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yc-export', 'routePath'=>'bonus/trace-down-yc-export', 'show'=>0,],
-            ['name'=>'荣衔奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yc', 'routePath'=>'bonus/trace-up-yc', 'show'=>1,],
-            ['name'=>'荣衔奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yc-export', 'routePath'=>'bonus/trace-up-yc-export', 'show'=>0,],
-            ['name'=>'服务奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-bd', 'routePath'=>'bonus/trace-down-bd', 'show'=>1,],
-            ['name'=>'服务奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-bd-export', 'routePath'=>'bonus/trace-down-bd-export', 'show'=>0,],
-            ['name'=>'服务奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-bd', 'routePath'=>'bonus/trace-up-bd', 'show'=>1,],
-            ['name'=>'服务奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-bd-export', 'routePath'=>'bonus/trace-up-bd-export', 'show'=>0,],
-            ['name'=>'推广奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-tg', 'routePath'=>'bonus/trace-down-tg', 'show'=>1,],
-            ['name'=>'推广奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-tg-export', 'routePath'=>'bonus/trace-down-tg-export', 'show'=>0,],
-            ['name'=>'推广奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-tg', 'routePath'=>'bonus/trace-up-tg', 'show'=>1,],
-            ['name'=>'推广奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-tg-export', 'routePath'=>'bonus/trace-up-tg-export', 'show'=>0,],
-            ['name'=>'消费奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-xf', 'routePath'=>'bonus/trace-down-xf', 'show'=>1,],
-            ['name'=>'消费奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-xf-export', 'routePath'=>'bonus/trace-down-xf-export', 'show'=>0,],
-            ['name'=>'消费奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-xf', 'routePath'=>'bonus/trace-up-xf', 'show'=>1,],
-            ['name'=>'消费奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-xf-export', 'routePath'=>'bonus/trace-up-xf-export', 'show'=>0,],
-            ['name'=>'业绩奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yj', 'routePath'=>'bonus/trace-down-yj', 'show'=>1,],
-            ['name'=>'业绩奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yj-export', 'routePath'=>'bonus/trace-down-yj-export', 'show'=>0,],
-            ['name'=>'业绩奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yj', 'routePath'=>'bonus/trace-up-yj', 'show'=>1,],
-            ['name'=>'业绩奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yj-export', 'routePath'=>'bonus/trace-up-yj-export', 'show'=>0,],
-            ['name'=>'共享奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gx', 'routePath'=>'bonus/trace-down-gx', 'show'=>1,],
-            ['name'=>'共享奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gx-export', 'routePath'=>'bonus/trace-down-gx-export', 'show'=>0,],
-            ['name'=>'共享奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gx', 'routePath'=>'bonus/trace-up-gx', 'show'=>1,],
-            ['name'=>'共享奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gx-export', 'routePath'=>'bonus/trace-up-gx-export', 'show'=>0,],
-            ['name'=>'管理奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gl', 'routePath'=>'bonus/trace-down-gl', 'show'=>1,],
-            ['name'=>'管理奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gl-export', 'routePath'=>'bonus/trace-down-gl-export', 'show'=>0,],
-            ['name'=>'管理奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gl', 'routePath'=>'bonus/trace-up-gl', 'show'=>1,],
-            ['name'=>'管理奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gl-export', 'routePath'=>'bonus/trace-up-gl-export', 'show'=>0,],
+//            ['name'=>'团队奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-qy', 'routePath'=>'bonus/trace-down-qy', 'show'=>1,],
+//            ['name'=>'团队奖下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-qy-export', 'routePath'=>'bonus/trace-down-qy-export', 'show'=>0,],
+//            ['name'=>'团队奖向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-qy', 'routePath'=>'bonus/trace-up-qy', 'show'=>1,],
+//            ['name'=>'团队奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-qy-export', 'routePath'=>'bonus/trace-up-qy-export', 'show'=>0,],
+//            ['name'=>'荣衔奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yc', 'routePath'=>'bonus/trace-down-yc', 'show'=>1,],
+//            ['name'=>'荣衔奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yc-export', 'routePath'=>'bonus/trace-down-yc-export', 'show'=>0,],
+//            ['name'=>'荣衔奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yc', 'routePath'=>'bonus/trace-up-yc', 'show'=>1,],
+//            ['name'=>'荣衔奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yc-export', 'routePath'=>'bonus/trace-up-yc-export', 'show'=>0,],
+//            ['name'=>'服务奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-bd', 'routePath'=>'bonus/trace-down-bd', 'show'=>1,],
+//            ['name'=>'服务奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-bd-export', 'routePath'=>'bonus/trace-down-bd-export', 'show'=>0,],
+//            ['name'=>'服务奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-bd', 'routePath'=>'bonus/trace-up-bd', 'show'=>1,],
+//            ['name'=>'服务奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-bd-export', 'routePath'=>'bonus/trace-up-bd-export', 'show'=>0,],
+//            ['name'=>'推广奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-tg', 'routePath'=>'bonus/trace-down-tg', 'show'=>1,],
+//            ['name'=>'推广奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-tg-export', 'routePath'=>'bonus/trace-down-tg-export', 'show'=>0,],
+//            ['name'=>'推广奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-tg', 'routePath'=>'bonus/trace-up-tg', 'show'=>1,],
+//            ['name'=>'推广奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-tg-export', 'routePath'=>'bonus/trace-up-tg-export', 'show'=>0,],
+//            ['name'=>'消费奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-xf', 'routePath'=>'bonus/trace-down-xf', 'show'=>1,],
+//            ['name'=>'消费奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-xf-export', 'routePath'=>'bonus/trace-down-xf-export', 'show'=>0,],
+//            ['name'=>'消费奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-xf', 'routePath'=>'bonus/trace-up-xf', 'show'=>1,],
+//            ['name'=>'消费奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-xf-export', 'routePath'=>'bonus/trace-up-xf-export', 'show'=>0,],
+//            ['name'=>'业绩奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yj', 'routePath'=>'bonus/trace-down-yj', 'show'=>1,],
+//            ['name'=>'业绩奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-yj-export', 'routePath'=>'bonus/trace-down-yj-export', 'show'=>0,],
+//            ['name'=>'业绩奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yj', 'routePath'=>'bonus/trace-up-yj', 'show'=>1,],
+//            ['name'=>'业绩奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-yj-export', 'routePath'=>'bonus/trace-up-yj-export', 'show'=>0,],
+//            ['name'=>'共享奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gx', 'routePath'=>'bonus/trace-down-gx', 'show'=>1,],
+//            ['name'=>'共享奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gx-export', 'routePath'=>'bonus/trace-down-gx-export', 'show'=>0,],
+//            ['name'=>'共享奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gx', 'routePath'=>'bonus/trace-up-gx', 'show'=>1,],
+//            ['name'=>'共享奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gx-export', 'routePath'=>'bonus/trace-up-gx-export', 'show'=>0,],
+//            ['name'=>'管理奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gl', 'routePath'=>'bonus/trace-down-gl', 'show'=>1,],
+//            ['name'=>'管理奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-gl-export', 'routePath'=>'bonus/trace-down-gl-export', 'show'=>0,],
+//            ['name'=>'管理奖贴向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gl', 'routePath'=>'bonus/trace-up-gl', 'show'=>1,],
+//            ['name'=>'管理奖向上追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-gl-export', 'routePath'=>'bonus/trace-up-gl-export', 'show'=>0,],
             ['name'=>'用户业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'user-perf', 'routePath'=>'bonus/user-perf', 'show'=>1,],
-            ['name'=>'荣衔业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'yc-perf', 'routePath'=>'bonus/yc-perf', 'show'=>1,],
-            ['name'=>'达标业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'perf-standard', 'routePath'=>'bonus/perf-standard', 'show'=>1,],
-            ['name'=>'达标业绩导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'perf-standard-export', 'routePath'=>'bonus/perf-standard-export', 'show'=>0,],
+//            ['name'=>'荣衔业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'yc-perf', 'routePath'=>'bonus/yc-perf', 'show'=>1,],
+//            ['name'=>'达标业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'perf-standard', 'routePath'=>'bonus/perf-standard', 'show'=>1,],
+//            ['name'=>'达标业绩导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'perf-standard-export', 'routePath'=>'bonus/perf-standard-export', 'show'=>0,],
 //            ['name'=>'复销奖向下追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-fx', 'routePath'=>'bonus/trace-down-fx', 'show'=>1,],
 //            ['name'=>'复销奖向下追溯导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-down-fx-export', 'routePath'=>'bonus/trace-down-fx-export', 'show'=>0,],
 //            ['name'=>'复销奖向上追溯', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'trace-up-fx', 'routePath'=>'bonus/trace-up-fx', 'show'=>1,],
@@ -391,7 +391,7 @@ return [
         'show'=>1,
         'child'=>[
             ['name'=>'导出文件', 'class'=>'', 'icon'=>'', 'controller'=>'file', 'action'=>'export', 'routePath'=>'file/export', 'show'=>1,],
-            ['name'=>'删除文件', 'class'=>'', 'icon'=>'', 'controller'=>'file', 'action'=>'export-delete', 'routePath'=>'file/export-delete', 'show'=>0,],
+//            ['name'=>'删除文件', 'class'=>'', 'icon'=>'', 'controller'=>'file', 'action'=>'export-delete', 'routePath'=>'file/export-delete', 'show'=>0,],
 
         ]
     ],
@@ -466,14 +466,14 @@ return [
             ['name'=>'站点设置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'base', 'routePath'=>'config/base', 'show'=>1,],
             ['name'=>'奖金设置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus-opt', 'routePath'=>'config/bonus-opt', 'show'=>1,],
             ['name'=>'奖金基本配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus', 'routePath'=>'config/bonus', 'show'=>0,],
-            ['name'=>'区域/复销奖配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus-dec-level', 'routePath'=>'config/bonus-dec-level', 'show'=>0,],
-            ['name'=>'育成/车房/养老配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus-emp-level', 'routePath'=>'config/bonus-emp-level', 'show'=>0,],
+//            ['name'=>'区域/复销奖配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus-dec-level', 'routePath'=>'config/bonus-dec-level', 'show'=>0,],
+//            ['name'=>'育成/车房/养老配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'bonus-emp-level', 'routePath'=>'config/bonus-emp-level', 'show'=>0,],
             ['name'=>'期数配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'period', 'routePath'=>'config/period', 'show'=>1,],
 //            ['name'=>'会员注册类型配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'reg-type', 'routePath'=>'config/reg-type', 'show'=>1,],
 //            ['name'=>'会员注册类型编辑', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'reg-type-edit', 'routePath'=>'config/reg-type-edit', 'show'=>0,],
 //            ['name'=>'维护注册协议', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'pact-edit', 'routePath'=>'config/pact-edit', 'show'=>0,],
             ['name'=>'第三方接口', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'api-opt', 'routePath'=>'config/api-opt', 'show'=>1,],
-            ['name'=>'OCR接口编辑', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'ocr-api-edit', 'routePath'=>'config/ocr-api-edit', 'show'=>0,],
+//            ['name'=>'OCR接口编辑', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'ocr-api-edit', 'routePath'=>'config/ocr-api-edit', 'show'=>0,],
             ['name'=>'短信接口编辑', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'ocr-api-edit', 'routePath'=>'config/ocr-api-edit', 'show'=>0,],
             ['name'=>'短信管理', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'sms', 'routePath'=>'config/sms', 'show'=>1,],
             ['name'=>'积分配置', 'class'=>'', 'icon'=>'', 'controller'=>'config', 'action'=>'score', 'routePath'=>'config/score', 'show'=>1,],

+ 2 - 0
backendApi/config/urlManagerRules.php

@@ -62,6 +62,8 @@ return [
             'GET order-standard-list' => 'order-standard-list',
             'POST import-order-standard-to-excel-table' => 'import-order-standard-to-excel-table',
             'POST import-order-standard' => 'import-order-standard',
+            'GET order-list-export-pdf/<orderSn>' => 'order-list-export-pdf',
+            'GET dec-order-list-export-pdf/<orderSn>' => 'dec-order-list-export-pdf',
         ],
     ],
     [

+ 1 - 1
backendApi/modules/v1/controllers/BonusController.php

@@ -2144,7 +2144,7 @@ class BonusController extends BaseController {
             'REAL_NAME' => 'UI.REAL_NAME',
             'userIds' => 'UB.USER_ID',
             'BONUS' => 'BONUS',
-            'RECONSUME_POINTS' => 'RECONSUME_POINTS',
+//            'RECONSUME_POINTS' => 'RECONSUME_POINTS',
             'CASH' => 'CASH',
             'IS_DEC' => 'UI.IS_DEC',
             'PERIOD_AT' => 'UI.PERIOD_AT',

+ 74 - 2
backendApi/modules/v1/controllers/ShopController.php

@@ -62,6 +62,7 @@ class ShopController extends BaseController {
             'SELL_TYPE'=> 'SELL_TYPE',
             'SELL_PRICE'=> 'SELL_PRICE',
             'PRICE_PV'=> 'PRICE_PV',
+            'CATEGORY_TYPE' => 'CATEGORY_TYPE',
         ]);
         $condition = $filter['condition'];
         $params = $filter['params'];
@@ -88,6 +89,7 @@ class ShopController extends BaseController {
             'SELL_TYPE'=> 'SELL_TYPE',
             'SELL_PRICE'=> 'SELL_PRICE',
             'PRICE_PV'=> 'PRICE_PV',
+            'CATEGORY_TYPE' => 'CATEGORY_TYPE',
         ]);
         $form = new ShopExportForm();
         $result = $form->run($filter, '商品列表');
@@ -113,7 +115,12 @@ class ShopController extends BaseController {
                 return static::notice(Form::formatErrorsForApi($formModel->getErrors()),400);
             }
         }
-        return static::notice(['sellType' => ShopGoods::SALE_TYPE, 'goodsType' => ShopGoods::GOODS_TYPE, 'giftType' => ShopGoods::GIFT_TYPE]);
+        return static::notice([
+            'sellType' => ShopGoods::SALE_TYPE,
+            'goodsType' => ShopGoods::GOODS_TYPE,
+            'giftType' => ShopGoods::GIFT_TYPE,
+            'categoryType' => ShopGoods::CATEGORY_TYPE,
+        ]);
     }
 
     /**
@@ -140,7 +147,15 @@ class ShopController extends BaseController {
         if ($data['TYPE'] == 1 || $data['TYPE'] == 2) {
             $data['SELL_DISCOUNT'] = ShopGoods::GOODS_TYPE[$data['TYPE']]['discount']/100;
         }
-        return static::notice(['goodsInfo'=>$data,'sellType' => ShopGoods::SALE_TYPE, 'goodsType' => ShopGoods::GOODS_TYPE, 'giftType' => ShopGoods::GIFT_TYPE]);
+        return static::notice(
+            [
+                'goodsInfo'=>$data,
+                'sellType' => ShopGoods::SALE_TYPE,
+                'goodsType' => ShopGoods::GOODS_TYPE,
+                'giftType' => ShopGoods::GIFT_TYPE,
+                'categoryType' => ShopGoods::CATEGORY_TYPE,
+            ]
+        );
     }
 
     /**
@@ -632,4 +647,61 @@ class ShopController extends BaseController {
         return static::notice('非法请求', 400);
     }
 
+    /**
+     * 报单表导出
+     * @return mixed
+     * @throws \yii\db\Exception
+     * @throws \yii\web\HttpException
+     */
+    public function actionOrderListExportPdf()
+    {
+        $orderSn = \Yii::$app->request->get('orderSn');
+
+        $filter = $this->filterCondition([
+            'SN'=> 'O.SN',
+            'USER_NAME'=> 'U.USER_NAME',
+            'MOBILE'=> 'O.MOBILE',
+            'PERIOD_NUM'=> 'O.PERIOD_NUM',
+            'CREATED_AT'=> 'O.CREATED_AT',
+        ]);
+
+        $filter['condition'] = ' AND O.IS_DELETE=0 AND O.SN=:SN';
+        $filter['params'] = [':SN' => $orderSn];
+
+        $form = new ShopExportForm();
+        $result = $form->run($filter, '订单列表');
+        if (!$result) {
+            return static::notice(Form::formatErrorsForApi($form->getErrors()), 400);
+        }
+        return static::notice('导出开始,请到文件管理-导出文件查看');
+    }
+
+    /**
+     * 报单表导出
+     * @return mixed
+     * @throws \yii\db\Exception
+     * @throws \yii\web\HttpException
+     */
+    public function actionDecOrderListExportPdf()
+    {
+        $orderSn = \Yii::$app->request->get('orderSn');
+
+        $filter = $this->filterCondition([
+            'SN'=> 'O.SN',
+            'USER_NAME'=> 'U.USER_NAME',
+            'MOBILE'=> 'O.MOBILE',
+            'PERIOD_NUM'=> 'O.PERIOD_NUM',
+            'CREATED_AT'=> 'O.CREATED_AT',
+        ]);
+
+        $filter['condition'] = ' AND O.IS_DELETE=0 AND O.SN=:SN';
+        $filter['params'] = [':SN' => $orderSn];
+
+        $form = new ShopExportForm();
+        $result = $form->run($filter, '订单列表');
+        if (!$result) {
+            return static::notice(Form::formatErrorsForApi($form->getErrors()), 400);
+        }
+        return static::notice('导出开始,请到文件管理-导出文件查看');
+    }
 }

+ 3 - 0
backendApi/modules/v1/controllers/UserController.php

@@ -885,6 +885,9 @@ class UserController extends BaseController
             $userInfo['CASH'] = Cash::getAvailableBalance($userInfo['ID']);
             $userInfo['RECONSUME_POINTS'] = Balance::getBalanceReconsumePoints($userInfo['ID']);
             $userInfo['EXCHANGE_POINTS'] = Balance::getBalanceExchangePoints($userInfo['ID']);
+            $userInfo['TRAVEL_POINTS'] = Balance::getAccountBalance($userInfo['ID'], 'travel_points');
+            $userInfo['CAR_POINTS'] = Balance::getAccountBalance($userInfo['ID'], 'car_points');
+            $userInfo['HOUSE_POINTS'] = Balance::getAccountBalance($userInfo['ID'], 'house_points');
             return static::notice($userInfo);
         }else{
             return static::notice('会员编号不存在', 400);

+ 64 - 19
backendApi/modules/v1/models/lists/bonus/BalanceList.php

@@ -147,11 +147,26 @@ class BalanceList extends \common\libs\dataList\DataList implements DataListInte
                         'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
                     ],
                 ],
-                'RECONSUME_POINTS' => [
-                    'header' => '会员复消积分',
+//                'RECONSUME_POINTS' => [
+//                    'header' => '会员复消积分',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['RECONSUME_POINTS'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '150',
+//                        'prop'=>'BONUS',
+//                    ],
+//                    'valueOther' => [
+//                        'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
+//                    ],
+//                ],
+                'CASH' => [
+                    'header' => '会员余额',
                     'value' => function($row) {
                         return (new Price([
-                            'value' => $row['RECONSUME_POINTS'],
+                            'value' => $row['CASH'],
                         ]))->result();
                     },
                     'headerOther' => [
@@ -177,21 +192,6 @@ class BalanceList extends \common\libs\dataList\DataList implements DataListInte
                         'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
                     ],
                 ],
-                'CASH' => [
-                    'header' => '会员余额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['CASH'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '150',
-                        'prop'=>'BONUS',
-                    ],
-                    'valueOther' => [
-                        'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
-                    ],
-                ],
 //                'CF' => [
 //                    'header' => '车房养老余额',
 //                    'value' => function($row) {
@@ -317,6 +317,51 @@ class BalanceList extends \common\libs\dataList\DataList implements DataListInte
 //                    'header' => '历史最高聘级',
 //                    'headerOther' => ['width' => '130'],
 //                ],
+                'TRAVEL_POINTS' => [
+                    'header' => '旅游积分',
+                    'value' => function($row) {
+                        return (new Price([
+                            'value' => $row['TRAVEL_POINTS'],
+                        ]))->result();
+                    },
+                    'headerOther' => [
+                        'width' => '150',
+                        'prop'=>'TRAVEL_POINTS',
+                    ],
+                    'valueOther' => [
+                        'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
+                    ],
+                ],
+                'CAR_POINTS' => [
+                    'header' => '名车积分',
+                    'value' => function($row) {
+                        return (new Price([
+                            'value' => $row['CAR_POINTS'],
+                        ]))->result();
+                    },
+                    'headerOther' => [
+                        'width' => '150',
+                        'prop'=>'CAR_POINTS',
+                    ],
+                    'valueOther' => [
+                        'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
+                    ],
+                ],
+                'HOUSE_POINTS' => [
+                    'header' => '豪宅积分',
+                    'value' => function($row) {
+                        return (new Price([
+                            'value' => $row['HOUSE_POINTS'],
+                        ]))->result();
+                    },
+                    'headerOther' => [
+                        'width' => '150',
+                        'prop'=>'HOUSE_POINTS',
+                    ],
+                    'valueOther' => [
+                        'tag'=>['type'=>'danger', 'size' => 'small', 'class'=>'no-border'],
+                    ],
+                ],
                 'PERIOD_AT' => '加入期数',
 //                'DEC_DEC_ROLE_NAME' => [
 //                    'header' => '所属报单中心级别',
@@ -399,7 +444,7 @@ class BalanceList extends \common\libs\dataList\DataList implements DataListInte
 //                'DEC_ROLE_NAME'=> ['isUserTable'=> true, 'name'=> '报单中心级别', 'other'=> 'decRole'],
 //                'SYSTEM_NAME'=> ['isUserTable'=> false, 'name'=> '体系名称', 'other'=> 'systems'],
                 'BONUS'=> ['isUserTable'=> false, 'name'=> '会员奖金余额'],
-                'RECONSUME_POINTS'=> ['isUserTable'=> false, 'name'=> '会员复消积分'],
+//                'RECONSUME_POINTS'=> ['isUserTable'=> false, 'name'=> '会员复消积分'],
                 'CASH'=> ['isUserTable'=> false, 'name'=> '会员余额'],
 //                'CF'=> ['isUserTable'=> false, 'name'=> '车房养老余额'],
 //                'LX'=> ['isUserTable'=> false, 'name'=> '领袖分红余额'],

+ 220 - 220
backendApi/modules/v1/models/lists/bonus/PeriodBonusList.php

@@ -276,7 +276,7 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
 //                    ],
 //                ],
                 'BONUS_TG' => [
-                    'header' => '推广奖',
+                    'header' => '销售奖金',
                     'value' => function($row) {
                         return (new Price([
                             'value' => $row['BONUS_TG'],
@@ -288,7 +288,7 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                     ],
                 ],
                 'ORI_BONUS_TG' => [
-                    'header' => '推广奖原金额',
+                    'header' => '销售奖金原金额',
                     'value' => function($row) {
                         return (new Price([
                             'value' => $row['ORI_BONUS_TG'],
@@ -300,7 +300,7 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                     ],
                 ],
                 'BONUS_QY' => [
-                    'header' => '团队奖',
+                    'header' => '绩效奖金',
                     'value' => function($row) {
                         return (new Price([
                             'value' => $row['BONUS_QY'],
@@ -312,7 +312,7 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                     ],
                 ],
                 'ORI_BONUS_QY' => [
-                    'header' => '团队奖原金额',
+                    'header' => '绩效奖金原金额',
                     'value' => function($row) {
                         return (new Price([
                             'value' => $row['ORI_BONUS_QY'],
@@ -419,66 +419,66 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                         'prop' => 'ORI_BONUS_BS_ABBR',
                     ],
                 ],
-                'BONUS_GX' => [
-                    'header' => '共享奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_GX'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_GX',
-                    ],
-                ],
-                'ORI_BONUS_GX' => [
-                    'header' => '共享奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_GX'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_GX',
-                    ],
-                ],
-                'REAL_BONUS_GX' => [
-                    'header' => '实发共享奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['REAL_BONUS_GX'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'REAL_BONUS_GX',
-                    ],
-                ],
-                'BONUS_BD' => [
-                    'header' => '服务奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_BD'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_BD',
-                    ],
-                ],
-                'ORI_BONUS_BD' => [
-                    'header' => '服务奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_BD'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_BD',
-                    ],
-                ],
+//                'BONUS_GX' => [
+//                    'header' => '共享奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_GX'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_GX',
+//                    ],
+//                ],
+//                'ORI_BONUS_GX' => [
+//                    'header' => '共享奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_GX'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_GX',
+//                    ],
+//                ],
+//                'REAL_BONUS_GX' => [
+//                    'header' => '实发共享奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['REAL_BONUS_GX'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'REAL_BONUS_GX',
+//                    ],
+//                ],
+//                'BONUS_BD' => [
+//                    'header' => '服务奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_BD'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_BD',
+//                    ],
+//                ],
+//                'ORI_BONUS_BD' => [
+//                    'header' => '服务奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_BD'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_BD',
+//                    ],
+//                ],
                 'BONUS_REAL' => [
                     'header' => '实发奖金',
                     'value' => function($row) {
@@ -515,18 +515,18 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                         'prop'=>'MANAGE_TAX',
                     ],
                 ],
-                'RECONSUME_POINTS' => [
-                    'header' => '复销积分',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['RECONSUME_POINTS'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'RECONSUME_POINTS',
-                    ],
-                ],
+//                'RECONSUME_POINTS' => [
+//                    'header' => '复销积分',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['RECONSUME_POINTS'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'RECONSUME_POINTS',
+//                    ],
+//                ],
                 'BONUS_INCOME' => [
                     'header' => '总收入',
                     'value' => function($row) {
@@ -539,156 +539,156 @@ class PeriodBonusList extends \common\libs\dataList\DataList implements DataList
                         'prop'=>'BONUS_INCOME',
                     ],
                 ],
-                'ORI_BONUS_STANDARD' => [
-                    'header' => '团队成长奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_STANDARD'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_STANDARD',
-                    ],
-                ],
+//                'ORI_BONUS_STANDARD' => [
+//                    'header' => '团队成长奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_STANDARD'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_STANDARD',
+//                    ],
+//                ],
                 'CALC_MONTH' => [
                     'header' => '结算月',
                     'headerOther' => [
                         'width' => '100',
                     ],
                 ],
-                'BONUS_XF' => [
-                    'header' => '消费奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_XF'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_XF',
-                    ],
-                ],
-                'ORI_BONUS_XF' => [
-                    'header' => '消费奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_XF'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_XF',
-                    ],
-                ],
-                'BONUS_YJ' => [
-                    'header' => '业绩奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_YJ'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_YJ',
-                    ],
-                ],
-                'ORI_BONUS_YJ' => [
-                    'header' => '业绩奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_YJ'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_YJ',
-                    ],
-                ],
-                'BONUS_YC' => [
-                    'header' => '荣衔奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_YC'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_YC',
-                    ],
-                ],
-                'ORI_BONUS_YC' => [
-                    'header' => '荣衔奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_YC'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_YC',
-                    ],
-                ],
-                'BONUS_VIP' => [
-                    'header' => 'VIP奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_VIP'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_VIP',
-                    ],
-                ],
-                'ORI_BONUS_VIP' => [
-                    'header' => 'VIP奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_VIP'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_VIP',
-                    ],
-                ],
-                'BONUS_GL' => [
-                    'header' => '管理奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['BONUS_GL'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'BONUS_GL',
-                    ],
-                ],
-                'ORI_BONUS_GL' => [
-                    'header' => '管理奖原金额',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['ORI_BONUS_GL'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'ORI_BONUS_GL',
-                    ],
-                ],
-                'REAL_BONUS_GL' => [
-                    'header' => '实发管理奖',
-                    'value' => function($row) {
-                        return (new Price([
-                            'value' => $row['REAL_BONUS_GL'],
-                        ]))->result();
-                    },
-                    'headerOther' => [
-                        'width' => '120',
-                        'prop'=>'REAL_BONUS_GL',
-                    ],
-                ],
+//                'BONUS_XF' => [
+//                    'header' => '消费奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_XF'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_XF',
+//                    ],
+//                ],
+//                'ORI_BONUS_XF' => [
+//                    'header' => '消费奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_XF'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_XF',
+//                    ],
+//                ],
+//                'BONUS_YJ' => [
+//                    'header' => '业绩奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_YJ'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_YJ',
+//                    ],
+//                ],
+//                'ORI_BONUS_YJ' => [
+//                    'header' => '业绩奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_YJ'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_YJ',
+//                    ],
+//                ],
+//                'BONUS_YC' => [
+//                    'header' => '荣衔奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_YC'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_YC',
+//                    ],
+//                ],
+//                'ORI_BONUS_YC' => [
+//                    'header' => '荣衔奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_YC'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_YC',
+//                    ],
+//                ],
+//                'BONUS_VIP' => [
+//                    'header' => 'VIP奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_VIP'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_VIP',
+//                    ],
+//                ],
+//                'ORI_BONUS_VIP' => [
+//                    'header' => 'VIP奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_VIP'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_VIP',
+//                    ],
+//                ],
+//                'BONUS_GL' => [
+//                    'header' => '管理奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['BONUS_GL'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'BONUS_GL',
+//                    ],
+//                ],
+//                'ORI_BONUS_GL' => [
+//                    'header' => '管理奖原金额',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['ORI_BONUS_GL'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'ORI_BONUS_GL',
+//                    ],
+//                ],
+//                'REAL_BONUS_GL' => [
+//                    'header' => '实发管理奖',
+//                    'value' => function($row) {
+//                        return (new Price([
+//                            'value' => $row['REAL_BONUS_GL'],
+//                        ]))->result();
+//                    },
+//                    'headerOther' => [
+//                        'width' => '120',
+//                        'prop'=>'REAL_BONUS_GL',
+//                    ],
+//                ],
 //                'BONUS_FW' => [
 //                    'header' => '服务奖',
 //                    'value' => function($row) {

+ 38 - 1
backendApi/modules/v1/models/lists/shop/DecOrderList.php

@@ -5,6 +5,7 @@ use common\helpers\Cache;
 use common\helpers\Tool;
 use common\libs\dataList\DataListInterface;
 use common\models\DecOrder;
+use common\models\Order;
 use common\models\User;
 use common\libs\dataList\column\DateTime;
 
@@ -24,7 +25,7 @@ class DecOrderList extends \common\libs\dataList\DataList implements DataListInt
     public function dataHandle()
     {
         $this->listData = DecOrder::lists($this->condition, $this->params, [
-            'select' => 'DO.*,U.USER_NAME USER_NAME,TU.USER_NAME TO_USER_NAME,TU.REAL_NAME,TU.ID_CARD,TU.MOBILE,TU.DEC_LV,DU.USER_NAME DEC_USER_NAME,DU.REAL_NAME DEC_REAL_NAME,RU.USER_NAME REC_USER_NAME,RU.REAL_NAME REC_REAL_NAME,CU.USER_NAME CON_USER_NAME,CU.REAL_NAME CON_REAL_NAME',
+            'select' => 'DO.*,U.USER_NAME USER_NAME,TU.USER_NAME TO_USER_NAME,TU.REAL_NAME,TU.ID_CARD,TU.MOBILE,TU.DEC_LV,DU.USER_NAME DEC_USER_NAME,DU.REAL_NAME DEC_REAL_NAME,RU.USER_NAME REC_USER_NAME,RU.REAL_NAME REC_REAL_NAME,CU.USER_NAME CON_USER_NAME,CU.REAL_NAME CON_REAL_NAME,O.*',
             'orderBy' => 'DO.CREATED_AT DESC, DO.ID DESC',
             'from' => DecOrder::tableName() . ' AS DO',
             'join' => [
@@ -33,6 +34,7 @@ class DecOrderList extends \common\libs\dataList\DataList implements DataListInt
                 ['LEFT JOIN', User::tableName() . ' AS DU', 'DO.DEC_ID=DU.ID'],
                 ['LEFT JOIN', User::tableName() . ' AS RU', 'DO.REC_USER_ID=RU.ID'],
                 ['LEFT JOIN', User::tableName() . ' AS CU', 'DO.CON_USER_ID=CU.ID'],
+                ['LEFT JOIN', Order::tableName() . ' AS O', 'DO.ORDER_SN=O.SN']
             ],
             'page' => $this->page,
             'pageSize' => $this->pageSize,
@@ -45,6 +47,7 @@ class DecOrderList extends \common\libs\dataList\DataList implements DataListInt
      */
     public function getColumn(){
         $decLevelConfig = Cache::getDecLevelConfig();
+        $regionConfig = Cache::getRegionConfig();
         if(!$this->columns){
             $this->columns = [
                 'ID' => null,
@@ -161,6 +164,40 @@ class DecOrderList extends \common\libs\dataList\DataList implements DataListInt
                     'header' => '报单时上级姓名',
                     'headerOther' => ['width' => '150'],
                 ],
+                'PROVINCE' => [
+                    'header' => '省',
+                    'headerOther' => ['width' => '120'],
+                    'value' => function ($row) use($regionConfig) {
+                        return $regionConfig[$row['PROVINCE']]['REGION_NAME'] ?? '';
+                    },
+                ],
+                'CITY' => [
+                    'header' => '市',
+                    'headerOther' => ['width' => '120'],
+                    'value' => function ($row) use($regionConfig) {
+                        return $regionConfig[$row['CITY']]['REGION_NAME'] ?? '';
+                    },
+                ],
+                'COUNTY' => [
+                    'header' => '区',
+                    'headerOther' => ['width' => '120'],
+                    'value' => function ($row) use($regionConfig) {
+                        return $regionConfig[$row['COUNTY']]['REGION_NAME'] ?? '';
+                    },
+                ],
+                'ADDRESS' => [
+                    'header' => '详细地址',
+                    'headerOther' => [
+                        'width' => '300',
+                    ],
+                ],
+                'EXPRESS_TYPE' => [
+                    'header' => '发货方式',
+                    'headerOther' => ['width' => '150'],
+                    'value' => function ($row) {
+                        return $row['EXPRESS_TYPE']==0 ? '邮寄' : '自提';
+                    },
+                ],
                 'PERIOD_NUM' => [
                     'header' => '期数',
                 ],

+ 11 - 2
backendApi/modules/v1/models/lists/shop/GoodsList.php

@@ -82,8 +82,16 @@ class GoodsList extends \common\libs\dataList\DataList implements DataListInterf
                     },
                     'headerOther' => ['width' => '150'],
                 ],
+                'CATEGORY_TYPE' => [
+                    'header' => '商品分类',
+                    'value' => function($row) {
+                        $categoryType = array_column(ShopGoods::CATEGORY_TYPE, NULL, 'id');
+                        return $categoryType[$row['CATEGORY_TYPE']]['name'] ?? '';
+                    },
+                    'headerOther' => ['width' => '150'],
+                ],
                 'SELL_TYPE' => [
-                    'header' => '复消购买方式',
+                    'header' => '购买方式',
                     'value' => function($row){
                         $sellType = ShopGoods::SALE_TYPE;
                         $sel = explode(',',$row['SELL_TYPE']);
@@ -165,9 +173,10 @@ class GoodsList extends \common\libs\dataList\DataList implements DataListInterf
                 'STATUS'=> ['name'=> '状态', 'other'=> 'select', 'selectData'=> [['id'=> 0, 'name'=> '已下架'],['id'=> 1, 'name'=> '已上架']]],
                 'GOODS_NAME'=> ['name'=> '商品名称'],
                 'GOODS_NO'=> ['name'=> '商品编号'],
-                'SELL_TYPE'=> ['name'=> '复消购买方式', 'other'=> 'select', 'selectData'=> [['id'=> 1, 'name'=> '余额购买'],['id'=> 2, 'name'=> '积分购买']]],
+//                'SELL_TYPE'=> ['name'=> '复消购买方式', 'other'=> 'select', 'selectData'=> [['id'=> 1, 'name'=> '余额购买'],['id'=> 2, 'name'=> '积分购买']]],
                 'SELL_PRICE'=> ['name'=> '销售价格'],
                 'PRICE_PV'=> ['name'=> '销售PV'],
+                'CATEGORY_TYPE' => ['name' => '商品分类', 'other'=> 'select', 'selectData'=> ShopGoods::CATEGORY_TYPE],
             ];
         }
         return $this->filterTypes;

+ 11 - 1
backendEle/src/views/config/period.vue

@@ -25,6 +25,15 @@
               <el-switch v-model="item.VALUE">
               </el-switch>
             </template>
+
+            <template v-else-if="item.INPUT_TYPE === '1'">
+              <el-form-item>
+                  <el-select v-model="item.VALUE" placeholder="请选择">
+                      <el-option v-for="item of item.OPTIONS" :label="item.label" :value="item.value" :key="item.label"></el-option>
+                  </el-select>
+              </el-form-item>
+            </template>
+
             <template v-else>
               <el-input v-model="item.VALUE" placeholder="请输入内容"></el-input>
             </template>
@@ -70,7 +79,8 @@ export default {
       network.postData('config/period', {
         calcYear: dateObj.getFullYear(),
         closeWeekDate: this.form.closeWeekDate,
-        closeTime: this.form.closeTime
+        closeTime: this.form.closeTime,
+        closeDays: this.form.closeDays
       }).then(response => {
         this.$message({
           message: response,

+ 43 - 1
backendEle/src/views/shop/dec-order-list.vue

@@ -21,7 +21,8 @@
       </el-table>
       <div class="white-box-footer">
         <el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`shop/dec-order-list-export`)">导出Excel</el-button>
-        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
+        <el-button type="primary" size="small" @click="handleExportPDF" v-show="permission.hasPermission(`shop/dec-order-list-export`)">导出PDF</el-button>
+          <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
                     @current-change="handleCurrentChange"></pagination>
       </div>
     </div>
@@ -108,6 +109,47 @@
 
         })
       },
+        handleExportPDF() {
+            if (this.multipleSelection.length === 0) {
+                this.$message({
+                    message: '请选择一条订单导出',
+                    type: 'error'
+                })
+                return false
+            }
+
+            // 提取订单ID
+            let orderSnList = this.multipleSelection.map((item) => item.SN.value || '');
+            // 去重
+            let orderSnSet = Array.from(new Set(orderSnList))
+            if (orderSnSet.length !== 1) {
+                this.$message({
+                    message: '每次只能导出一条订单',
+                    type: 'error'
+                })
+                return false
+            }
+
+            this.$confirm(`确定要导出当前数据吗?`, '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                // 导出时只需要订单ID即可
+                let orderSn = orderSnSet[0]
+                network.getData(`shop/dec-order-list-export-pdf/${orderSn}`).then(response => {
+                    this.$message({
+                        message: response,
+                        type: 'success'
+                    })
+                })
+            }).catch(response => {
+                this.$message({
+                    message: response,
+                    type: 'error'
+                })
+            })
+        },
     }
   }
 

+ 40 - 20
backendEle/src/views/shop/goods-add.vue

@@ -6,19 +6,26 @@
                 <el-form-item label="商品名称">
                     <el-input v-model="form.goodsName"></el-input>
                 </el-form-item>
-                <el-form-item label="商品来源">
+                <!-- <el-form-item label="商品来源">
                     <el-select v-model="form.type" placeholder="请选择商品来源">
                         <el-option v-for="(item,index) in goodsType" :key="index" :label="item.name"
                                    :value="index"></el-option>
                     </el-select>
+                </el-form-item> -->
+                <el-form-item label="会员折扣">
+                    <el-input v-model="form.sellDiscount"></el-input>
                 </el-form-item>
                 <el-form-item label="商品类型">
                     <el-checkbox  v-for="(value,key) in GiftTypeArr" v-model="form.giftType[key-1]" :key="key" >{{value.name}}</el-checkbox>
                 </el-form-item>
-                <el-form-item label="出售方式">
+                <!-- <el-form-item label="复消购买方式">
                     <el-checkbox  v-for="(value,key) in sellType" v-model="form.sellType[key-1]" :key="key" >{{value.name}}</el-checkbox>
+                </el-form-item> -->
+                <el-form-item label="商品分类">
+                    <el-select v-model="form.categoryType" placeholder="">
+                        <el-option v-for="item in categoryType" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                    </el-select>
                 </el-form-item>
-
                 <el-form-item label="商品编号">
                     <el-input v-model="form.goodsNo"></el-input>
                 </el-form-item>
@@ -31,7 +38,7 @@
                 <el-form-item label="销售价格">
                     <el-input v-model="form.sellPrice"></el-input>
                 </el-form-item>
-                <el-form-item label="价格PV	">
+                <el-form-item label="价格PV" v-show="pvDisabled">
                     <el-input v-model="form.pricePv"></el-input>
                 </el-form-item>
                 <!-- <el-form-item label="兑换积分">
@@ -105,18 +112,29 @@
                     discount:'',
                     cover:'',
                     textarea:'',
+                    sellDiscount:'',
+                    categoryType: '',
                 },
                 submitButtonStat: false,
                 goodsType:[],
                 GiftTypeArr:[],
+                categoryType: [],
                 sellType:null,
                 width:'100px',
                 height:'100px',
+                pvDisabled: true,
             }
         },
         watch:{
             dialogVisible(newVal,oldVal){
                 console.log(newVal,oldVal)
+            },
+            // 监听商品分类,控制PV是否展示
+            'form.categoryType': {
+                deep: true,
+                handler(modern, origin) {
+                    this.pvDisabled = (parseInt(modern) === 1)
+                }
             }
         },
         methods: {
@@ -131,7 +149,7 @@
                 this.dialogVisible = true;
                 this.file=file;
                 // console.log(file);
-                
+
             },
             handleDownload(file) {
                 console.log(file);
@@ -157,24 +175,25 @@
                 let filterData = this.filterModel
                 let vueObj = this
                 network.getPageData(this, 'shop/goods-add', page, pageSize, this.filterModel, response=>{
-                    console.log(response)
+                    this.categoryType = response.categoryType
                     this.goodsType=response.goodsType
                     this.GiftTypeArr=response.giftType
                     this.sellType=response.sellType
-                    this.form.sellType=this.form.sellType.map((item,index)=>{
-                      return response.sellType.some(val=>(index+1).toString()==val)
-                    })
+                    // this.form.sellType=this.form.sellType.map((item,index)=>{
+                    //   return response.sellType.some(val=>(index+1).toString()==val)
+                    // })
                 })
-            },addSubmit() {
+            },
+            addSubmit() {
                 this.submitButtonStat = true
                 let path = 'shop/goods-add';
 
-                let sellType =[]
-                this.form.sellType.map((item,index)=>{
-                  if(item){
-                    sellType.push((index+1).toString())
-                  }
-                });
+                // let sellType =[]
+                // this.form.sellType.map((item,index)=>{
+                //   if(item){
+                //     sellType.push((index+1).toString())
+                //   }
+                // });
 
                 let sen_gift=[];
                 this.form.giftType.map((item,index)=>{
@@ -185,10 +204,13 @@
 
                 let postData = {
                     goodsName: this.form.goodsName,
+                    sellDiscount: this.form.sellDiscount,
                     discount: this.form.type.discount,
                     type: this.form.type,
                     giftType: sen_gift,
-                    sellType: sellType,
+                    // sellType: sellType,
+                    sellType: this.form.sellType,
+                    categoryType: this.form.categoryType,
                     goodsNo: this.form.goodsNo,
                     unit: this.form.unit,
                     marketPrice: this.form.marketPrice,
@@ -199,11 +221,9 @@
                     content: this.form.content,
                     sort: this.form.sort,
                     cover: this.form.cover,
-
                 }
 
                 return network.postData(path, postData).then(response => {
-                    console.log(response);
                     this.$message({
                         message: response,
                         type: 'success'
@@ -239,4 +259,4 @@
 .up_load{
     width: 100px;
 }
-</style>
+</style>

+ 54 - 31
backendEle/src/views/shop/index.vue

@@ -18,7 +18,7 @@
                 </el-table-column>
                 <el-table-column fixed="right" label="操作" width="180">
                     <template slot-scope="scope">
-                        <el-dropdown size="small" trigger="click" v-if="permission.hasPermission(`shop/goods-edit`)||permission.hasPermission(`shop/goods-delete`)">
+                        <el-dropdown size="small" trigger="click" v-if="permission.hasPermission(`shop/goods-edit`) || permission.hasPermission(`shop/goods-delete`)">
                             <el-button type="primary" size="small" @click.stop="">
                                 操作该数据<i class="el-icon-arrow-down el-icon--right"></i>
                             </el-button>
@@ -70,19 +70,26 @@
                     <el-form-item label="商品名称">
                         <el-input v-model="form.goodsName"></el-input>
                     </el-form-item>
-                    <el-form-item label="商品来源">
+                    <!-- <el-form-item label="商品来源">
                         <el-select v-model="form.type">
                             <el-option v-for="(item,index) in goodsType" :key="index" :label="item.name"
                                        :value="index"></el-option>
                         </el-select>
+                    </el-form-item> -->
+                    <el-form-item label="会员折扣">
+                        <el-input v-model="form.sellDiscount"></el-input>
                     </el-form-item>
                     <el-form-item label="商品类型">
                         <el-checkbox  v-for="(value,index) in GiftTypeArr" v-model="value.checked" :key="index" >{{value.name}}</el-checkbox>
                     </el-form-item>
-                    <el-form-item label="出售方式">
+                    <!-- <el-form-item label="复消购买方式">
                          <el-checkbox  v-for="(value,index) in sell_type" v-model="value.checked" :key="index" >{{value.name}}</el-checkbox>
+                    </el-form-item> -->
+                    <el-form-item label="商品分类">
+                        <el-select v-model="form.categoryType">
+                            <el-option v-for="item in categoryType" :key="item.id" :label="item.name" :value="item.id" ></el-option>
+                        </el-select>
                     </el-form-item>
-
                     <el-form-item label="商品编号">
                         <el-input v-model="form.goodsNo"></el-input>
                     </el-form-item>
@@ -95,7 +102,7 @@
                     <el-form-item label="销售价格" p>
                         <el-input v-model="form.sellPrice"></el-input>
                     </el-form-item>
-                    <el-form-item label="价格PV	">
+                    <el-form-item label="价格PV" v-show="pvDisabled">
                         <el-input v-model="form.pricePv"></el-input>
                     </el-form-item>
                     <el-form-item label="兑换积分" v-show="false">
@@ -181,7 +188,7 @@
                 dialogEditFormVisible: false,
                 dialogEditLoading: false,
                 form:{
-                    sellType:[],
+                    // sellType:[],
                     goodsName:'',
                     type:'',
                     giftType:[],
@@ -197,12 +204,17 @@
                     discount:'',
                     cover:'',
                     textarea:'',
+                    sellDiscount:'',
+                    categoryType: '',
+                    sellType: 1,
                 },
                 submitButtonStat: false,
                 goodsType:[],
                 GiftTypeArr:[],
                 sell_type:[],
-                img_show:true
+                categoryType: [],
+                img_show:true,
+                pvDisabled: true,
             }
         },
         methods: {
@@ -239,6 +251,7 @@
                 network.getData('shop/goods-edit', {id: this.auditId}).then(response => {
                     vueObj.dialogEditLoading = false
                     vueObj.goodsType=response.goodsType
+                    vueObj.categoryType = response.categoryType
 
                     let gift=response.goodsInfo.GIFT_TYPE;
                     let gift_type=response.giftType;
@@ -256,22 +269,22 @@
                     }
                     vueObj.GiftTypeArr=giftType
 
-                    let sell=response.goodsInfo.SELL_TYPE;
-                    let sell_type=response.sellType;
-                    let sellType=[];
-                    if(sell.length>0){
-                        for(let i in sell_type){
-                            sellType.push({key:i,name:sell_type[i].name,checked:false})
-                            sell.map((item,index)=>{
-                                if(item==i){
-                                    sellType[i-1].checked=true;
-                                }
-                            }) 
-                        }
-                    }
-                    vueObj.sell_type=sellType;
-
+                    // let sell=response.goodsInfo.SELL_TYPE;
+                    // let sell_type=response.sellType;
+                    // let sellType=[];
+                    // if(sell.length>0){
+                    //     for(let i in sell_type){
+                    //         sellType.push({key:i,name:sell_type[i].name,checked:false})
+                    //         sell.map((item,index)=>{
+                    //             if(item==i){
+                    //                 sellType[i-1].checked=true;
+                    //             }
+                    //         })
+                    //     }
+                    // }
+                    vueObj.sell_type=response.goodsInfo.SELL_TYPE;
                     vueObj.form.goodsName=response.goodsInfo.GOODS_NAME
+                    vueObj.form.sellDiscount=response.goodsInfo.SELL_DISCOUNT
                     vueObj.form.goodsNo=response.goodsInfo.GOODS_NO
                     vueObj.form.type=response.goodsInfo.TYPE
                     vueObj.form.unit=response.goodsInfo.UNIT
@@ -284,10 +297,11 @@
                     vueObj.form.sort=response.goodsInfo.SORT
                     vueObj.form.id=response.goodsInfo.ID
                     vueObj.form.cover=response.goodsInfo.COVER
+                    vueObj.form.categoryType=parseInt(response.goodsInfo.CATEGORY_TYPE)
                     // vueObj.form.sellType=vueObj.form.sellType.map((item,index)=>{
                     //   return response.goodsInfo.SELL_TYPE.some(val=>(index+1).toString()==val)
                     //   })
-                    
+
                     this.$forceUpdate()
 
                 })
@@ -300,13 +314,13 @@
                 })
                 let path = 'shop/goods-edit'
 
-                let sen_sell=[];
-                this.sell_type.map((item,index)=>{
-                    if(item.checked){
-                        sen_sell.push(item.key);
-                    }
-                })
-                this.form.sellType=sen_sell;
+                // let sen_sell=[];
+                // this.sell_type.map((item,index)=>{
+                //     if(item.checked){
+                //         sen_sell.push(item.key);
+                //     }
+                // })
+                // this.form.sellType=sen_sell;
 
                 let sen_gift=[];
                 this.GiftTypeArr.map((item,index)=>{
@@ -315,6 +329,7 @@
                     }
                 })
                 this.form.giftType=sen_gift;
+                this.form.sellType = 1
 
                 network.postData(path, {...this.form}).then(response => {
                     this.$message({
@@ -402,7 +417,15 @@
                 })
             },
         },
-
+        watch:{
+            // 监听商品分类,控制PV是否展示
+            'form.categoryType': {
+                deep: true,
+                handler(modern, origin) {
+                    this.pvDisabled = (parseInt(modern) === 1)
+                }
+            }
+        },
     }
 
 </script>

+ 42 - 0
backendEle/src/views/shop/order-list.vue

@@ -34,6 +34,7 @@
       </el-table>
       <div class="white-box-footer">
         <el-button type="success" size="small" @click="handleExport" v-show="permission.hasPermission(`shop/order-list-export`)">导出Excel</el-button>
+        <el-button type="primary" size="small" @click="handleExportPDF" v-show="permission.hasPermission(`shop/order-list-export`)">导出PDF</el-button>
         <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"
                     @current-change="handleCurrentChange"></pagination>
       </div>
@@ -130,6 +131,47 @@
 
         })
       },
+        handleExportPDF() {
+            if (this.multipleSelection.length === 0) {
+                this.$message({
+                    message: '请选择一条订单导出',
+                    type: 'error'
+                })
+                return false
+            }
+
+            // 提取订单ID
+            let orderSnList = this.multipleSelection.map((item) => item.SN.value || '');
+            // 去重
+            let orderSnSet = Array.from(new Set(orderSnList))
+            if (orderSnSet.length !== 1) {
+                this.$message({
+                    message: '每次只能导出一条订单',
+                    type: 'error'
+                })
+                return false
+            }
+
+            this.$confirm(`确定要导出当前数据吗?`, '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'info'
+            }).then(() => {
+                // 导出时只需要订单ID即可
+                let orderSn = orderSnSet[0]
+                network.getData(`shop/order-list-export-pdf/${orderSn}`).then(response => {
+                    this.$message({
+                        message: response,
+                        type: 'success'
+                    })
+                })
+            }).catch(response => {
+                this.$message({
+                    message: response,
+                    type: 'error'
+                })
+            })
+        },
       handleEdit() {
         // 进入修改订单页面
       },

+ 13 - 1
common/config/params.php

@@ -200,7 +200,7 @@ return [
         'exchange_points' => [
             'name' => 'bonus',
             'label' => '兑换积分余额',
-        ]
+        ],
 //        'cf' => [
 //            'name' => 'cf',
 //            'label' => '车房养老奖余额',
@@ -209,6 +209,18 @@ return [
 //            'name' => 'lx',
 //            'label' => '领袖分红奖余额',
 //        ],
+        'travel_points' => [
+            'name' => 'travel_points',
+            'label' => '旅游积分余额',
+        ],
+        'car_points' => [
+            'name' => 'car_points',
+            'label' => '名车积分余额',
+        ],
+        'house_points' => [
+            'name' => 'house_points',
+            'label' => '豪宅积分余额',
+        ],
     ],
     'auditStatus' => [
         'un' => [

+ 5 - 0
common/helpers/Constant.php

@@ -0,0 +1,5 @@
+<?php
+
+/* ********************【服务通用状态码】************************* */
+const SUCCESS_CODE = 200;   // 成功
+const FAILED_CODE = 500;    // 失败

+ 89 - 103
common/helpers/bonus/BonusCalc.php

@@ -1638,16 +1638,15 @@ class BonusCalc extends BaseObject {
         if (!$this->_isCalcMonth) {
             return true;
         }
-        // 限定条件,只计算旅游奖、名车奖、豪宅奖
-        if (!in_array($bonusConfig['CONFIG_NAME'], $this->_calcZone)) {
-            return true;
-        }
 
         // 达标条件:聘级、级别、奖项比例
         $config = json_decode($bonusConfig['OPTIONS'], true);
+        // 奖金总比例
         $mate = $bonusConfig['VALUE'] / 100;
-        $minEmployLevel = $config['employLevel'];
-        $minDeclarationLevel = $config['declarationLevel'];
+        // 会员级别
+        $minDecLevel = $config['OPTIONS']['declarationLevel'] ?? [];
+        // 会员聘级
+        $minEmpLevel = $config['OPTIONS']['employLevel'] ?? [];
 
         // 月度公司总PV
         $monthTotalPV = PerfMonth::find()
@@ -1659,24 +1658,11 @@ class BonusCalc extends BaseObject {
             return true;
         }
 
-        // 奖项获取条件:聘级
-        $minEmpLV = "'" . implode("','", $minEmployLevel) . "'";
-        // 计算奖金条件
-        if ($bonusConfig['CONFIG_NAME'] == 'openTravel') {
-            // 旅游奖:聘级3级
-            $query = "CALC_MONTH=:CALC_MONTH AND LEVEL_ID IN ({$minEmpLV})";
-            $param = [':CALC_MONTH' => $this->_calcYearMonth];
-        } else {
-            // 名车奖:聘级4 && 钻卡    豪宅奖:聘级5 && 钻卡
-            $query = "CALC_MONTH=:CALC_MONTH AND LEVEL_ID IN({$minEmpLV}) AND LAST_DEC_LV=:DEV_LV";
-            $param = [':CALC_MONTH' => $this->_calcYearMonth, ':DEV_LV' => $minDeclarationLevel];
-        }
-
         // 基于蓝星奖结果计算符合获奖条件的会员
         $userBonusData = CalcBonusBS::find()
             ->yearMonth($this->_calcYearMonth)
-            ->where($query, $param)
-            ->select('USER_ID,LEVEL_ID,LAST_DEC_LV,LAST_EMP_LV,LAST_STATUS')
+            ->where('CALC_MONTH=:CALC_MONTH', [':CALC_MONTH' => $this->_calcYearMonth])
+            ->select('USER_ID,LEVEL_ID,LAST_DEC_LV,LAST_EMP_LV,LAST_STATUS,RECONSUME_POINTS')
             ->groupBy('USER_ID')
             ->asArray()
             ->all();
@@ -1693,8 +1679,25 @@ class BonusCalc extends BaseObject {
             return true;
         }
 
+        // 奖金标识
+        if ($bonusConfig['CONFIG_NAME'] == 'openTravel') {
+            $bonusCacheKey = 'calc:travel:bonus_';
+        } else if ($bonusConfig['CONFIG_NAME'] == 'openCar') {
+            $bonusCacheKey = 'calc:car:bonus_';
+        } else {
+            $bonusCacheKey = 'calc:house:bonus_';
+        }
+
         $insertBonusData = [];
         foreach($userBonusData as $userBonus) {
+            // 会员级别+聘级都达到要求才会发放奖金
+            if (in_array($userBonus['LAST_DEC_LV'], $minDecLevel) && in_array($userBonus['LEVEL_ID'], $minEmpLevel)) {
+                // 放入缓存
+                CalcCache::zoneBonus($userBonus['USER_ID'], $this->_periodNum, $bonusCacheKey, $amount);
+                // 加入月奖的会员
+                CalcCache::addHasMonthBonusUsers($userBonus['USER_ID'], $this->_periodNum);
+            }
+
             $insertBonusData[] = [
                 'ID' => SnowFake::instance()->generateId(),
                 'USER_ID' => $userBonus['USER_ID'],
@@ -1733,13 +1736,17 @@ class BonusCalc extends BaseObject {
         }
         // 从缓存获取分页有收入的会员信息
         $allData = CalcBonusBS::findUseDbCalc()
-            ->where('PERIOD_NUM=:PERIOD_NUM AND ORI_BONUS_MNT > 0', [':PERIOD_NUM' => $this->_periodNum])
+            ->where('PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum])
             ->groupBy('USER_ID')
             ->offset($offset)
             ->limit($this->_limit)
             ->asArray()
             ->all();
         if ($allData) {
+            // 达标条件:会员级别:钻卡
+            $config = json_decode($this->_sysConfig['openGL']['OPTIONS'], true);
+            $minDecLevel = $config['mntDec'] ?? [];
+
             foreach ($allData as $user) {
                 //扣除相应的复消积分和管理费
                 $deductData = $this->deduct($user['USER_ID'], $user['ORI_BONUS_MNT']);
@@ -1747,17 +1754,12 @@ class BonusCalc extends BaseObject {
                 $manageTax = $deductData['manageTax']; // 管理费
                 $point = $deductData['reConsumePoints'] + $user['RECONSUME_POINTS'];// 复消积分
 
-                // 获取会员的报单级别
-                $userBaseInfo = CalcCache::getUserInfo($user['USER_ID'], $this->_periodNum);
-                $decLevelConfig = $this->_decLevelConfig;
-                $nowDecLevelID = $decLevelConfig[$userBaseInfo['DEC_LV']]['ID'] ?? '';
                 // 管理奖钻卡发放
-                if ($nowDecLevelID == '67ABCE0ECE705575E055736AECE8644D') {
-                    // 添加到有奖励信息的数据中
-                    CalcCache::addHasBonusUsers($user['USER_ID'], $this->_periodNum);
-                    //CalcCache::addHasMonthBonusUsers($user['USER_ID'], $this->_periodNum);
+                if (in_array($user['LAST_DEC_LV'], $minDecLevel)) {
                     // 把对碰后的奖金存入缓存中
                     CalcCache::bonus($user['USER_ID'], $this->_periodNum, 'BONUS_BS_MNT', $user['ORI_BONUS_MNT'], $deductData);
+                    // 加入月奖的会员
+                    CalcCache::addHasMonthBonusUsers($user['USER_ID'], $this->_periodNum);
                 }
 
                 // 更新蓝星奖金存储过程的实发金额数据
@@ -1787,38 +1789,38 @@ class BonusCalc extends BaseObject {
         }
         // 从缓存获取分页有收入的会员信息
         $allData = CalcBonusBS::findUseDbCalc()
-            ->where('PERIOD_NUM=:PERIOD_NUM AND ORI_BONUS_ABBR > 0', [':PERIOD_NUM' => $this->_periodNum])
+            ->where('PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum])
             ->groupBy('USER_ID')
             ->offset($offset)
             ->limit($this->_limit)
             ->asArray()
             ->all();
         if ($allData) {
+            // 达标条件:会员级别:金卡、钻卡
+            $config = json_decode($this->_sysConfig['openGL']['OPTIONS'], true);
+            $minDecLevel = $config['abbrDec'] ?? [];
+
             foreach ($allData as $user) {
                 //扣除相应的复消积分和管理费
                 $deductData = $this->deduct($user['USER_ID'], $user['ORI_BONUS_ABBR']);
                 $realBonusBs = $deductData['surplus']; // 扣除管理费和复消积分后的实发蓝星奖金
                 $manageTax = $deductData['manageTax']; // 管理费
                 $point = $deductData['reConsumePoints'] + $user['RECONSUME_POINTS'];// 复消积分
-                // 获取会员的报单级别
-                $userBaseInfo = CalcCache::getUserInfo($user['USER_ID'], $this->_periodNum);
-                $decLevelConfig = $this->_decLevelConfig;
-                $nowDecLevelID = $decLevelConfig[$userBaseInfo['DEC_LV']]['ID'] ?? '';
 
                 // 业绩奖金卡、钻卡发放
-                if (in_array($nowDecLevelID, ['67ABCCE20A9F5553E055736AECE8644D', '67ABCE0ECE705575E055736AECE8644D'])) {
-                    // 添加到有奖励信息的数据中
-                    CalcCache::addHasBonusUsers($user['USER_ID'], $this->_periodNum);
-                    //CalcCache::addHasMonthBonusUsers($user['USER_ID'], $this->_periodNum);
+                if (in_array($user['LAST_DEC_LV'], $minDecLevel)) {
                     // 把对碰后的奖金存入缓存中
                     CalcCache::bonus($user['USER_ID'], $this->_periodNum, 'BONUS_BS_ABBR', $user['ORI_BONUS_ABBR'], $deductData);
+                    // 加入月奖的会员
+                    CalcCache::addHasMonthBonusUsers($user['USER_ID'], $this->_periodNum);
                 }
 
                 // 更新蓝星业绩奖金存储过程的实发金额数据
-                CalcBonusBS::updateAll(['AMOUNT_ABBR' => $realBonusBs,
+                CalcBonusBS::updateAll([
+                    'AMOUNT_ABBR' => $realBonusBs,
                     'MANAGE_TAX_ABBR' => $manageTax,
                     'RECONSUME_POINTS' => $point],
-                'USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM',
+            'USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM',
                     [':USER_ID' => $user['USER_ID'], ':PERIOD_NUM' => $this->_periodNum]);
             }
             return $this->calcBonusBsYJ($offset + $this->_limit);
@@ -3376,6 +3378,9 @@ class BonusCalc extends BaseObject {
         $standardBonus = CalcCache::standardBonus($userId, $this->_periodNum);
         $baseInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
         $perfData = CalcCache::nowPeriodPerf($userId, $this->_periodNum);
+        $travelBonus = CalcCache::zoneBonus($userId, $this->_periodNum, CalcCache::REDIS_KEY_PREFIX_TRAVEL_BONUS);
+        $carBonus = CalcCache::zoneBonus($userId, $this->_periodNum, CalcCache::REDIS_KEY_PREFIX_CAR_BONUS);
+        $houseBonus = CalcCache::zoneBonus($userId, $this->_periodNum, CalcCache::REDIS_KEY_PREFIX_HOUSE_BONUS);
         $empLv = $baseInfo['EMP_LV'];
 //        if($this->_isCalcMonth){
 //            $empLv = $this->nowMonthPerfData($userId)['LAST_EMP_LV'];
@@ -3401,26 +3406,34 @@ class BonusCalc extends BaseObject {
         //     }
         // }
 
-
         //没有共享和管理奖
-        $bonusReal = $bonus['BONUS_BD'] + $bonus['BONUS_TG'] + $bonus['BONUS_XF'] + $bonus['BONUS_YJ'] + $bonus['BONUS_QY'] + $bonus['BONUS_YC'] + $bonus['BONUS_YC_EXTRA'] + $bonus['BONUS_VIP'] + $standardBonus;
+        $bonusReal = $bonus['BONUS_BD'] + $bonus['BONUS_TG'] + $bonus['BONUS_XF'] + $bonus['BONUS_YJ'] + $bonus['BONUS_QY'] + $bonus['BONUS_YC'] + $bonus['BONUS_YC_EXTRA'] + $bonus['BONUS_VIP'] + $standardBonus + $bonus['BONUS_BS_MNT'] + $bonus['BONUS_BS_ABBR'];
         $realBonusGx = 0;
         $realBonusGl = 0;
         $realBonusBs = 0; // 蓝星管理奖. BlueStar
-        $blueStartAmount = 0;
-        $buleStartOriBonus = 0;
-        $buleStartManageTax = 0;
+        $blueStartOriBonus = 0;
+        $blueStartManageTax = 0;
         $exchangePoints = 0; // 蓝星奖管理奖. 产生的兑换积分
 
-        $realBonusBsMnt = 0; // 蓝星管理奖. BlueStar
-        $blueStartOriBonusMnt = 0;
+        $realBonusBsMnt = 0; // 蓝星管理奖——实发奖金
+        $blueStartOriBonusMnt = 0;  // 蓝星管理奖——原奖金
+        $blueStartManageTaxMnt = 0;   // 蓝星管理奖——管理费
 
-        $realBonusBsAbbr = 0; // 蓝星业绩奖. BlueStar
-        $blueStartOriBonusAbbr = 0;
+        $realBonusBsAbbr = 0; // 蓝星业绩奖——实发奖金
+        $blueStartOriBonusAbbr = 0; // 蓝星业绩奖——原奖金
+        $blueStartManageTaxAbbr = 0;   // 蓝星业绩奖——管理费
         if( $this->_isCalcMonth ) {
-            //查看是否复消300
-            $monthPerfData = CalcCache::nowMonthPerf($userId, $this->_periodNum);
-            $fxPvStatus = $monthPerfData['PV_PCS_FX'] >= $this->_sysConfig['monthPcsPvFxCondition']['VALUE'];
+            // 逻辑改成,用户此月累计消费总额大于等于配置,取消订单类型的配置
+            $userMonthTotal = PerfMonth::find()
+                ->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$userId, 'CALC_MONTH'=>$this->_calcYearMonth])
+                ->asArray()
+                ->one();
+
+            // 个人月消费PV大于配置值,才会计算发放蓝星奖
+            $fxPvStatus = false;
+            if (isset($userMonthTotal['PV_PCS']) && $userMonthTotal['PV_PCS'] >= $this->_sysConfig['monthPcsPvFxCondition']['VALUE']) {
+                $fxPvStatus = true;
+            }
             // BONUS_REAL 字段是发到用户的真实奖金
             if ( $fxPvStatus ) {
                 // 管理奖改成了蓝星奖,但是对于用户来说依旧叫管理奖.字段改成bs.
@@ -3440,16 +3453,21 @@ class BonusCalc extends BaseObject {
                 ->orderBy('CREATED_AT DESC')
                 ->asArray()
                 ->all();
+
                 $userBS = is_array($userBS) ? reset($userBS) : [];
                 $blueStartAmount = isset($userBS['AMOUNT']) && !empty($userBS['AMOUNT']) ? $userBS['AMOUNT'] : 0; // 奖金
-                $buleStartOriBonus = isset($userBS['ORI_BONUS']) && !empty($userBS['ORI_BONUS']) ? $userBS['ORI_BONUS'] : 0; // 原奖金
-                // $buleStartManageTax = isset($userBS['MANAGE_TAX']) && !empty($userBS['MANAGE_TAX']) ? $userBS['MANAGE_TAX'] : 0; // 管理费
+                $blueStartOriBonus = isset($userBS['ORI_BONUS']) && !empty($userBS['ORI_BONUS']) ? $userBS['ORI_BONUS'] : 0; // 原奖金
+                $blueStartManageTax = isset($userBS['MANAGE_TAX']) && !empty($userBS['MANAGE_TAX']) ? $userBS['MANAGE_TAX'] : 0; // 管理费
 
-                $realBonusBsMnt = $userBS['AMOUNT_MNT'] ?? 0; // 蓝星管理奖. 奖金
+                $realBonusBsMnt = $userBS['AMOUNT_MNT'] ?? 0; // 蓝星管理奖. 实发奖金
                 $blueStartOriBonusMnt = $userBS['ORI_BONUS_MNT'] ?? 0; // 蓝星管理奖. 原奖金
+                $blueStartManageTaxMnt = $userBS['MANAGE_TAX_MNT'] ?? 0; // 蓝星管理奖. 管理费
 
                 $realBonusBsAbbr = $userBS['AMOUNT_ABBR'] ?? 0; // 蓝星业绩奖. 奖金
                 $blueStartOriBonusAbbr = $userBS['ORI_BONUS_ABBR'] ?? 0; // 蓝星业绩奖. 原奖金
+                $blueStartManageTaxAbbr = $userBS['MANAGE_TAX_ABBR'] ?? 0; // 蓝星业绩奖. 管理费
+
+                $blueStartManageTax += $blueStartManageTaxMnt + $blueStartManageTaxAbbr; // 管理费
 
                 $monthSumData = CalcBonus::findUseSlaves()
                 ->select('SUM(BONUS_GX) AS BONUS_GX_SUM, SUM(BONUS_GL) AS BONUS_GL_SUM')
@@ -3461,57 +3479,15 @@ class BonusCalc extends BaseObject {
                 )
                 ->asArray()
                 ->one();
-                $bonusGxSum = $monthSumData['BONUS_GX_SUM'] ?? 0;
-                $bonusGlSum = $monthSumData['BONUS_GL_SUM'] ?? 0;
-                $realBonusGx += $bonusGxSum + $bonus['BONUS_GX'];
-                $realBonusGl += $bonusGlSum + $bonus['BONUS_GL'];
                 $realBonusBs = $blueStartAmount; // 蓝星奖直接取数据库中算好的值PRODUCT_POINT
-                $bonusReal += $realBonusGx + $realBonusBs + $realBonusGl;
                 $exchangePoints = isset($userBS['PRODUCT_POINT']) && !empty($userBS['PRODUCT_POINT']) ? $userBS['PRODUCT_POINT'] : 0; // 兑换积分
 
-                $bonus['BONUS_TOTAL'] = $bonus['BONUS_TOTAL'] + $buleStartOriBonus; // 管理奖在存储过程计算,这里单独加上管理奖(即蓝星奖)
+                // 蓝星奖总奖金:管理奖+业绩奖
+                $blueStartOriBonus = $blueStartOriBonusMnt + $blueStartOriBonusAbbr;
+                $bonus['BONUS_TOTAL'] = $bonus['BONUS_TOTAL'] + $blueStartOriBonus; // 管理奖在存储过程计算,这里单独加上管理奖(即蓝星奖)
                 unset($monthSumData, $bonusGxSum, $bonusGlSum);
             }
         }
-        // if( $this->_isCalcMonth ) {
-        //     // 将查看是否复消300的逻辑,改成月结时判断当前月有一周活跃则本月活跃
-        //     // 1. 获取此业绩期的月份
-        //     $periodInfo = Period::getInfoByPeriodNum($this->_periodNum);
-            
-        //     $calcMonth = $periodInfo['CALC_YEAR'].'-'.$periodInfo['CALC_MONTH']; // 2025-7
-        //     // 获取此月的第一天和最后一天时间戳
-        //     $fday = date('Y-m-01', strtotime($calcMonth));
-        //     $lday = date('Y-m-d', strtotime("$fday +1 month -1 day"));
-        //     $ftime = strtotime($fday);
-        //     $ltime = strtotime($lday.' 23:59:59');
-        //     // 2. 根据业绩期的月份,判断用户是否是活跃状态.
-        //     $fxPvStatus = PerfActiveUser::findUseDbCalc()
-        //     ->select('USER_ID')
-        //     ->where("USER_ID=:USER_ID ", [':USER_ID' => $userId])
-        //     ->andWhere(['or',
-        //         [
-        //             'and',
-        //             ['>=', 'SRATR_AT', $ftime],
-        //             ['<=', 'SRATR_AT', $ltime]
-        //         ],
-        //         [
-        //             'and',
-        //             ['>=', 'END_AT', $ftime],
-        //             ['<=', 'END_AT', $ltime]
-        //         ]
-        //     ])
-        //     ->asArray()
-        //     ->all();
-        //     if ( !empty($fxPvStatus) ) {//加上本期和往期的共享和管理奖
-        //         $monthSumData = CalcBonus::findUseSlaves()->select('SUM(BONUS_GX) AS BONUS_GX_SUM, SUM(BONUS_GL) AS BONUS_GL_SUM')->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$userId, 'CALC_MONTH'=>$this->_calcYearMonth])->asArray()->one();
-        //         $bonusGxSum = $monthSumData['BONUS_GX_SUM'] ?? 0;
-        //         $bonusGlSum = $monthSumData['BONUS_GL_SUM'] ?? 0;
-        //         $realBonusGx += $bonusGxSum + $bonus['BONUS_GX'];
-        //         $realBonusGl += $bonusGlSum + $bonus['BONUS_GL'];
-        //         $bonusReal += $realBonusGx + $realBonusGl;
-        //         unset($monthSumData, $bonusGxSum, $bonusGlSum);
-        //     }
-        // }
 
         $result = [
             'USER_ID' => $userId,
@@ -3547,7 +3523,7 @@ class BonusCalc extends BaseObject {
             'BONUS_YC' => $bonus['BONUS_YC'] + $bonus['BONUS_YC_EXTRA'],
             'BONUS_VIP' => $bonus['BONUS_VIP'],
             'RECONSUME_POINTS' => $bonus['RECONSUME_POINTS'],
-            'MANAGE_TAX' => $bonus['MANAGE_TAX'],
+            'MANAGE_TAX' => $blueStartManageTax,    // 管理费
             'BONUS_INCOME'=>$bonus['INCOME_TOTAL'],
             'BONUS_REAL'=>  $bonusReal,
             'BONUS_TOTAL'=>$bonus['BONUS_TOTAL'],
@@ -3561,15 +3537,21 @@ class BonusCalc extends BaseObject {
             'REAL_BONUS_GX' => $realBonusGx,
             'ORI_BONUS_GL' => $bonus['ORI_BONUS_GL'],
             'REAL_BONUS_GL' => $realBonusGl,
+
             'BONUS_BS' => $realBonusBs, // 新的管理奖金,即蓝星管理奖
-            'ORI_BONUS_BS' => $buleStartOriBonus, // 蓝星管理奖金原奖金,即包含管理费
+            'ORI_BONUS_BS' => $blueStartOriBonus, // 蓝星管理奖金原奖金,即包含管理费
             'REAL_BONUS_BS' => $realBonusBs, // 实发蓝星管理奖金
+
             'BONUS_BS_MNT' => $realBonusBsMnt, // 蓝星管理奖
             'ORI_BONUS_BS_MNT' => $blueStartOriBonusMnt, // 蓝星管理奖金原奖金,即包含管理费
             'REAL_BONUS_BS_MNT' => $realBonusBsMnt, // 实发蓝星管理奖金
+            'MANAGE_TAX_MNT' => $blueStartManageTaxMnt,  // 实发蓝星管理——管理费
+
             'BONUS_BS_ABBR' => $realBonusBsAbbr, // 蓝星业绩奖
             'ORI_BONUS_BS_ABBR' => $blueStartOriBonusAbbr, // 蓝星业绩奖金原奖金,即包含管理费
             'REAL_BONUS_BS_ABBR' => $realBonusBsAbbr, // 实发蓝星业绩奖金
+            'MANAGE_TAX_ABBR' => $blueStartManageTaxAbbr, // 实发蓝星业绩奖——管理费
+
             'ORI_BONUS_GL_BD' => $bonus['ORI_BONUS_GL_BD'],
             'ORI_BONUS_GL_FX' => $bonus['ORI_BONUS_GL_FX'],
             'ORI_BONUS_QY' => $bonus['ORI_BONUS_QY'],
@@ -3579,6 +3561,10 @@ class BonusCalc extends BaseObject {
             'ORI_BONUS_VIP' => $bonus['ORI_BONUS_VIP'],
             'ORI_BONUS_STANDARD' => $standardBonus,
 
+            'BONUS_TRAVEL' => $travelBonus, // 旅游奖
+            'BONUS_CAR' => $carBonus, // 名车奖
+            'BONUS_HOUSE' => $houseBonus, // 豪宅奖
+
             //以下没有用
             'BONUS_FW' => 0,
             'BONUS_FX' => $bonus['BONUS_FX'],

+ 38 - 0
common/helpers/bonus/BonusSend.php

@@ -318,6 +318,8 @@ class BonusSend extends BaseObject {
                             'GX' => $data['BONUS_GX'],
                             'GL' => $data['BONUS_GL'],
                             'BS' => $data['BONUS_BS'],
+                            'BS_MNT' => $data['BONUS_BS_MNT'],
+                            'BS_ABBR' => $data['BONUS_BS_ABBR'],
 
                             'ORI_QY' => $data['ORI_BONUS_QY'],
                             'ORI_YC' => $data['ORI_BONUS_YC'],
@@ -329,6 +331,8 @@ class BonusSend extends BaseObject {
                             'ORI_GX' => $data['ORI_BONUS_GX'],
                             'ORI_GL' => $data['ORI_BONUS_GL'],
                             'ORI_BS' => $data['ORI_BONUS_BS'],
+                            'ORI_BS_MNT' => $data['ORI_BONUS_BS_MNT'],
+                            'ORI_BS_ABBR' => $data['ORI_BONUS_BS_ABBR'],
 
                             'RECONSUME_POINTS_TOTAL' => $data['RECONSUME_POINTS'],
                             'EXCHANGE_POINTS_TOTAL' => $data['EXCHANGE_POINTS'],
@@ -342,6 +346,40 @@ class BonusSend extends BaseObject {
 //                        $this->_teamworkBonus($data['USER_ID'], $periodAmount, $key);
                     }
 
+                    // 旅游奖
+                    if ($data['BONUS_TRAVEL'] > 0) {
+                        Balance::changeUserBonus($data['USER_ID'], 'travel_points', $data['BONUS_TRAVEL'], [
+                            'CALC_ID' => $data['ID'],
+                            'REMARK' => 'From ' . $periodNum . '期',
+                            'PERIOD_NUM' => $periodNum,
+                            'TRAVEL' => $data['BONUS_TRAVEL'],
+                            'DEAL_TYPE_ID' => DealType::TRAVEL_SEND,
+                            'SORT' => $key * 10,
+                        ]);
+                    }
+                    // 名车奖
+                    if ($data['BONUS_CAR'] > 0) {
+                        Balance::changeUserBonus($data['USER_ID'], 'car_points', $data['BONUS_CAR'], [
+                            'CALC_ID' => $data['ID'],
+                            'REMARK' => 'From ' . $periodNum . '期',
+                            'PERIOD_NUM' => $periodNum,
+                            'HOUSE' => $data['BONUS_CAR'],
+                            'DEAL_TYPE_ID' => DealType::CAR_SEND,
+                            'SORT' => $key * 10,
+                        ]);
+                    }
+                    // 豪宅奖
+                    if ($data['BONUS_HOUSE'] > 0) {
+                        Balance::changeUserBonus($data['USER_ID'], 'house_points', $data['BONUS_HOUSE'], [
+                            'CALC_ID' => $data['ID'],
+                            'REMARK' => 'From ' . $periodNum . '期',
+                            'PERIOD_NUM' => $periodNum,
+                            'HOUSE' => $data['BONUS_HOUSE'],
+                            'DEAL_TYPE_ID' => DealType::HOUSE_SEND,
+                            'SORT' => $key * 10,
+                        ]);
+                    }
+
                     //发放重消积分
                     if ($data['RECONSUME_POINTS'] > 0) {
                         Balance::changeUserBonus($data['USER_ID'], 'reconsume_points', $data['RECONSUME_POINTS'], [

+ 30 - 0
common/helpers/bonus/CalcCache.php

@@ -49,6 +49,9 @@ class CalcCache {
     const REDIS_KEY_PREFIX_STANDARD_BONUS = 'calc:standard:bonus_';
     const REDIS_KEY_PREFIX_YC_BONUS = 'calc:yc:bonus_';
     const REDIS_KEY_PREFIX_FW_BONUS = 'calc:fw:bonus_';
+    const REDIS_KEY_PREFIX_TRAVEL_BONUS = 'calc:travel:bonus_';
+    const REDIS_KEY_PREFIX_CAR_BONUS = 'calc:car:bonus_';
+    const REDIS_KEY_PREFIX_HOUSE_BONUS = 'calc:house:bonus_';
     const REDIS_KEY_PREFIX_HAS_PERF_USER = 'calc:hasPerfUser_';
     const REDIS_KEY_PREFIX_HAS_MONTH_PERF_USER = 'calc:hasMonthPerfUser_';
     const REDIS_KEY_PREFIX_HAS_STANDARD_MONTH_PERF_USER = 'calc:hasStandardMonthPerfUser_';
@@ -96,6 +99,9 @@ class CalcCache {
 //    const INCOME_QY_BONUS = 'BONUS_QY';
     const INCOME_QY_BONUS_BD = 'BONUS_QY_BD';
     const INCOME_QY_BONUS_FX = 'BONUS_QY_FX';
+    const INCOME_BONUS_TRAVEL = 'BONUS_TRAVEL';
+    const INCOME_BONUS_CAR = 'BONUS_CAR';
+    const INCOME_BONUS_HOUSE = 'BONUS_HOUSE';
     const INCOME_BONUS_LIST = [
 //        self::INCOME_TG_BONUS,
 //        self::INCOME_XF_BONUS,
@@ -107,6 +113,9 @@ class CalcCache {
     const NOT_SEND_BONUS_LIST = [
         self::INCOME_QY_BONUS_BD,
         self::INCOME_QY_BONUS_FX,
+        self::INCOME_BONUS_TRAVEL,
+        self::INCOME_BONUS_CAR,
+        self::INCOME_BONUS_HOUSE,
     ];
 
     const FROM_MEANS_BD = 'BD';
@@ -1534,6 +1543,27 @@ class CalcCache {
         return $value;
     }
 
+    public static function zoneBonus($userId, $periodNum, $bonusCacheKey, $bonus = 0.00) {
+        $cacheKey = $bonusCacheKey . $periodNum;
+
+        $value = 0.00;
+        if( $bonus > 0 ) {
+            Yii::$app->redis->hset($cacheKey, $userId, $bonus);
+            $value = $bonus;
+            //加入有奖金的会员中
+            self::addHasBonusUsers($userId, $periodNum);
+        }else {
+            $cacheValue = \Yii::$app->redis->hget($cacheKey, $userId);
+            if ($cacheValue) {
+                $value = $cacheValue;
+            }
+            unset($cacheValue);
+        }
+
+        unset($cacheKey, $userId, $periodNum, $bonus);
+        return $value;
+    }
+
     /**
      * 设置车房总系数
      * @param $periodNum

+ 100 - 1
common/helpers/user/Balance.php

@@ -17,6 +17,7 @@ use common\models\FlowBonus;
 use common\models\FlowCF;
 use common\models\FlowLX;
 use common\models\FlowReconsumePoints;
+use common\models\FlowZonePoints;
 use common\models\InvoiceFlow;
 use common\models\Period;
 use common\models\DeclarationLevel;
@@ -42,6 +43,36 @@ class Balance {
     const CF_BALANCE_LOCK_KEY = 'CF';
     const LX_BALANCE_LOCK_KEY = 'LX';
     const INVOICE_BALANCE_LOCK_KEY = 'Invoice';
+    const TRAVEL_POINTS_BALANCE_LOCK_KEY = 'travelPoints';
+    const CAR_POINTS_BALANCE_LOCK_KEY = 'carPoints';
+    const HOUSE_POINTS_BALANCE_LOCK_KEY = 'housePoints';
+
+    const BALANCE_TYPE = [
+        'exchange' => [
+            'id'    => 'exchange',
+            'title' => '兑换点数',
+            'attr'  => 'EXCHANGE_POINTS',
+            'pv'    => false,
+        ],
+        'travel_points' => [
+            'id'    => 'travel_points',
+            'title' => '旅游积分',
+            'attr'  => 'TRAVEL_POINTS',
+            'pv'    => false,
+        ],
+        'car_points' => [
+            'id'    => 'car_points',
+            'title' => '名车积分',
+            'attr'  => 'CAR_POINTS',
+            'pv'    => false,
+        ],
+        'house_points' => [
+            'id'    => 'house_points',
+            'title' => '豪宅积分',
+            'attr'  => 'HOUSE_POINTS',
+            'pv'    => false,
+        ],
+    ];
 
     /**
      * 发票流水
@@ -182,6 +213,17 @@ class Balance {
         }
     }
 
+    /**
+     * 查询会员账户余额.
+     * @param $userId
+     * @param $payType
+     * @return int|mixed
+     */
+    public static function getAccountBalance($userId, $payType) {
+        $oneData = UserBonus::find()->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
+        return !$oneData ? 0 : $oneData[Balance::BALANCE_TYPE[$payType]['attr']] ?? 0;
+    }
+
     /**
      * 改变会员的余额
      * @param $userId
@@ -222,6 +264,15 @@ class Balance {
             case 'LX':
                 $lockKey = self::LX_BALANCE_LOCK_KEY . $userId;
                 break;
+            case 'TRAVEL_POINTS':
+                $lockKey = self::TRAVEL_POINTS_BALANCE_LOCK_KEY . $userId;
+                break;
+            case 'CAR_POINTS':
+                $lockKey = self::CAR_POINTS_BALANCE_LOCK_KEY . $userId;
+                break;
+            case 'HOUSE_POINTS':
+                $lockKey = self::HOUSE_POINTS_BALANCE_LOCK_KEY . $userId;
+                break;
             default:
                 throw new Exception('流水类型错误');
         }
@@ -274,7 +325,21 @@ class Balance {
                 }
                 if (isset($params['BS'])) {
                     $paramData['BS_TOTAL'] = new Expression('BS_TOTAL + '.$params['BS']);
-                    //$oneUserBonusModel->GL_TOTAL += $params['GL'];
+                }
+                if (isset($params['BS_MNT'])) {
+                    $paramData['BS_MNT_TOTAL'] = new Expression('BS_MNT_TOTAL + '.$params['BS_MNT']);
+                }
+                if (isset($params['BS_ABBR'])) {
+                    $paramData['BS_ABBR_TOTAL'] = new Expression('BS_ABBR_TOTAL + '.$params['BS_ABBR']);
+                }
+                if (isset($params['TRAVEL_POINTS'])) {
+                    $paramData['TRAVEL_POINTS_TOTAL'] = new Expression('TRAVEL_POINTS_TOTAL + ' . $params['TRAVEL_POINTS']);
+                }
+                if (isset($params['CAR_POINTS'])) {
+                    $paramData['CAR_POINTS_TOTAL'] = new Expression('CAR_POINTS_TOTAL + '.$params['CAR_POINTS']);
+                }
+                if (isset($params['HOUSE_POINTS'])) {
+                    $paramData['HOUSE_POINTS_TOTAL'] = new Expression('HOUSE_POINTS_TOTAL + '.$params['HOUSE_POINTS']);
                 }
                 if (isset($params['RECONSUME_POINTS_TOTAL'])) {
                     $paramData['RECONSUME_POINTS_TOTAL'] = new Expression('RECONSUME_POINTS_TOTAL + '.$params['RECONSUME_POINTS_TOTAL']);
@@ -329,6 +394,14 @@ class Balance {
                     $paramData['ORI_BS_TOTAL'] = new Expression('ORI_BS_TOTAL + '.$params['ORI_BS']);
                     //$oneUserBonusModel->ORI_GL_TOTAL += $params['ORI_GL'];
                 }
+                if (isset($params['ORI_BS_MNT'])) {
+                    $paramData['BS_MNT_ORI_TOTAL'] = new Expression('BS_MNT_ORI_TOTAL + '.$params['ORI_BS_MNT']);
+                    //$oneUserBonusModel->ORI_GL_TOTAL += $params['ORI_GL'];
+                }
+                if (isset($params['ORI_BS_ABBR'])) {
+                    $paramData['BS_ABBR_ORI_TOTAL'] = new Expression('BS_ABBR_ORI_TOTAL + '.$params['ORI_BS_ABBR']);
+                    //$oneUserBonusModel->ORI_GL_TOTAL += $params['ORI_GL'];
+                }
 
                 if (isset($params['BONUS_TOTAL'])) {
                     $paramData['BONUS_TOTAL'] = new Expression('BONUS_TOTAL + '.$params['BONUS_TOTAL']);
@@ -384,6 +457,22 @@ class Balance {
                     $paramData['BS_TOTAL'] = $params['BS'];
                     //$oneUserBonusModel->GL_TOTAL += $params['GL'];
                 }
+                if (isset($params['BS_MNT'])) {
+                    $paramData['BS_MNT_TOTAL'] = $params['BS_MNT'];
+                }
+                if (isset($params['BS_ABBR'])) {
+                    $paramData['BS_ABBR_TOTAL'] = $params['BS_ABBR'];
+                }
+                if (isset($params['TRAVEL_POINTS'])) {
+                    $paramData['TRAVEL_POINTS_TOTAL'] = $params['TRAVEL_POINTS'];
+                }
+                if (isset($params['CAR_POINTS'])) {
+                    $paramData['CAR_POINTS_TOTAL'] = $params['CAR_POINTS'];
+                }
+                if (isset($params['HOUSE_POINTS'])) {
+                    $paramData['HOUSE_POINTS_TOTAL'] = $params['HOUSE_POINTS'];
+                }
+
                 if (isset($params['RECONSUME_POINTS_TOTAL'])) {
 //                    $paramData['RECONSUME_POINTS_TOTAL'] = new Expression('RECONSUME_POINTS_TOTAL + '.$params['RECONSUME_POINTS_TOTAL']);
                     $paramData['RECONSUME_POINTS_TOTAL'] = $params['RECONSUME_POINTS_TOTAL'];
@@ -436,6 +525,12 @@ class Balance {
                     $paramData['ORI_BS_TOTAL'] = $params['ORI_BS'];
                     //$oneUserBonusModel->ORI_GL_TOTAL += $params['ORI_GL'];
                 }
+                if (isset($params['ORI_BS_MNT'])) {
+                    $paramData['BS_MNT_ORI_TOTAL'] = $params['ORI_BS_MNT'];
+                }
+                if (isset($params['ORI_BS_ABBR'])) {
+                    $paramData['BS_ABBR_ORI_TOTAL'] = $params['ORI_BS_ABBR'];
+                }
 
                 if (isset($params['BONUS_TOTAL'])) {
 //                    $paramData['BONUS_TOTAL'] = new Expression('BONUS_TOTAL + '.$params['BONUS_TOTAL']);
@@ -500,6 +595,10 @@ class Balance {
                 FlowCF::insertOne($flowInsertData);
             } elseif (strtolower($type) == 'lx') {
                 FlowLX::insertOne($flowInsertData);
+            } elseif (in_array(strtolower($type), ['travel_points', 'car_points', 'house_points'])) {
+                // 这3个奖流水在一个表,需要加二级标识码
+                $flowInsertData['WALLET_TYPE'] = strtolower($type);
+                FlowZonePoints::insertOne($flowInsertData);
             }
             unset($flowInsertData);
             RedisLock::instance()->unlock($lockKey);

+ 235 - 2
common/libs/export/BaseExport.php

@@ -9,6 +9,7 @@ use common\helpers\http\RemoteUploadApi;
 use common\helpers\Tool;
 use common\libs\dataList\DataList;
 use common\models\Export;
+use common\models\Region;
 use Yii;
 use yii\base\Exception;
 use yii\base\StaticInstanceTrait;
@@ -129,8 +130,8 @@ class BaseExport extends Component {
      * @return string|null
      * @throws \Exception
      */
-    public function getFileName() {
-        $this->fileName = date('YmdHis', Date::nowTime()) . random_int(1000, 9999) . '.csv';
+    public function getFileName($ext = '.csv') {
+        $this->fileName = date('YmdHis', Date::nowTime()) . random_int(1000, 9999) . $ext;
         return $this->fileName;
     }
 
@@ -420,4 +421,236 @@ class BaseExport extends Component {
         }
         return $taskKey;
     }
+
+    /**
+     * 生成
+     * @return bool
+     * @throws Exception
+     * @throws \yii\base\InvalidConfigException
+     * @throws \yii\httpclient\Exception
+     */
+    public function generatePDF() {
+        $this->getParams();
+        if (!$this->params) {
+            throw new Exception('无法获取需要的参数');
+        }
+        $path = __DS__ . $this->getSaveBasePath() . __DS__ . $this->getSavePath();
+        $realFile = $path . __DS__ . $this->getFileName('.pdf');
+
+        $this->completed = false;
+        $this->getExportId();
+        $this->getUserId();
+        $fileNameUpdated = false;
+
+        // 获取列表数据及表头
+        $this->_listModel = new $this->listModelClass();
+        $this->_listModel->isExport = true;
+
+        // 查询订单数据
+        $oderList = $this->_loopWriteDataPDF($realFile, $fileNameUpdated);
+        if ($oderList) {
+            $userId = '';
+            $userName = '';
+            $address = '';
+            $mobile = '';
+            $orderAt = '';
+            $orderDetails = '';
+            $orderSn = '';
+            $orderAmount = 0;  // 合计总额
+            $orderNums = 0; // 合计总数
+            foreach ($oderList as $key => $value) {
+                $provinceName = $value['PROVINCE'] ? Region::getCnName($value['PROVINCE']) : '';
+                $cityName = $value['CITY'] ? Region::getCnName($value['CITY']) : '';
+                $countyName = $value['COUNTY'] ? Region::getCnName($value['COUNTY']) : '';
+
+                $userId = $value['USER_NAME'];
+                $userName = $value['CREATE_USER_NAME'];
+                $address = $provinceName . $cityName . $countyName . $value['ADDRESS'];
+                $mobile = $value['MOBILE'];
+                $orderAt = $value['PAY_AT'];
+                $orderSn = $value['SN'];
+                // 总价
+                $totalAmount = $value['BUY_NUMS'] * $value['REAL_PRICE'];
+                $orderAmount += $totalAmount;
+                $orderNums += $value['BUY_NUMS'];
+                // 订单详情
+                $orderDetails .= <<<EOT
+                    <tr>
+                        <td>{$value['SKU_CODE']}</td>
+                        <td>{$value['GOODS_TITLE']}</td>
+                        <td>{$value['BUY_NUMS']}</td>
+                        <td>{$value['REAL_PRICE']}</td>
+                        <td>{$totalAmount}</td> 
+                    </tr>
+EOT;
+            }
+
+            // 订单基本信息
+            $orderBase = <<<ORDER
+                <table border="1" style="table-layout: fixed; padding: 10px 20px;" width="100%">
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员编号</td>
+                        <td width="70%">{$userId}</td>
+                    </tr>
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员名字</td>
+                        <td width="70%">{$userName}</td>
+                    </tr>
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员地址</td>
+                        <td width="70%">{$address}</td>
+                    </tr>
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员电话</td>
+                        <td width="70%">{$mobile}</td>
+                    </tr>
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单编号</td>
+                        <td width="70%">{$orderSn}</td>
+                    </tr>
+                    <tr>
+                        <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单日期</td>
+                        <td width="70%">{$orderAt}</td>
+                    </tr>
+                    <tr>
+                        <td class="bg" style="font-weight: bold; font-size: 14px; text-align: center;">订单明细</td>
+                        <td class="bg"></td>
+                    </tr>
+                </table>
+ORDER;
+
+            $l['a_meta_charset'] = 'UTF-8';
+            $l['a_meta_dir'] = 'ltr';
+            $l['a_meta_language'] = 'zh';
+            $l['w_page'] = '页面';
+
+            $context = <<<ORDER
+                <!doctype html>
+                <html lang="en">
+                <head>
+                    <meta charset="UTF-8" />
+                    <title>订单详情</title>
+                    <style>
+                        table {
+                            border-collapse: collapse;
+                        }
+                        table td, table th {
+                            border: 1px solid #ccc;
+                            padding: 10px 30px;
+                            border-collapse: collapse;
+                        }
+                        td {
+                            padding: 120px;
+                        }
+                        .bg {
+                            background-color: #ccc;
+                        }
+                    </style>
+                </head>
+                <body>
+                    <div class="content">
+                        <p style="text-align: center; font-weight: bold; font-size: 22px;"><b>订单详情</b><br></p>
+                        <div>
+                            <div style="display: block; width: 100%;">
+                                {$orderBase}
+                                
+                                <table border="1" width="100%" style="padding: 10px 20px; text-align: center;">
+                                    <tr>
+                                        <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">商品编号</th>
+                                        <th width="30%" style="font-size: 14px; font-weight: bold; text-align: center;">商品名称</th>
+                                        <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">数量</th>
+                                        <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">单价</th>
+                                        <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">总价</th>
+                                    </tr>
+                                    {$orderDetails}
+                                    <tr>
+                                        <td colspan="2">合计</td>
+                                        <td>{$orderNums}</td>
+                                        <td></td>
+                                        <td>{$orderAmount}</td>
+                                    </tr>
+                                </table>
+                            </div>
+                            
+                            <div style="width: 100%; margin-top: 50px; height: 30px;">
+                                <table width="100%" style="border: none; padding: 10px 20px; text-align: center;">
+                                    <tr style="border: none;">
+                                        <td width="70%" style="border: none;"></td>
+                                        <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">签名:</td>
+                                    </tr>
+                                    <tr style="border: none;">
+                                        <td width="70%" style="border: none;"></td>
+                                        <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">日期:</td>
+                                    </tr>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+                </body>
+                </html>
+ORDER;
+
+            require_once (\Yii::$app->vendorPath . '/tecnickcom/tcpdf/tcpdf.php');
+
+            $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
+            // 设置打印模式
+            $pdf->SetCreator(PDF_CREATOR);
+            $pdf->SetAuthor('DaZe');
+            $pdf->SetTitle($orderSn);
+            $pdf->SetSubject('TCPDF Tutorial');
+            $pdf->SetKeywords('TCPDF, PDF, example, test, guide');
+            // 是否显示页眉
+            $pdf->setPrintHeader(false);
+            // 设置页眉字体
+            $pdf->setHeaderFont(Array('dejavusans', '', '12'));
+            // 页眉距离顶部的距离
+            $pdf->SetHeaderMargin('5');
+            // 是否显示页脚
+            $pdf->setPrintFooter(false);
+            // 设置默认等宽字体
+            $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
+            // 设置行高
+            $pdf->setCellHeightRatio(1);
+            // 设置左、上、右的间距
+            $pdf->SetMargins('10', '10', '10');
+            // 设置是否自动分页  距离底部多少距离时分页
+            $pdf->SetAutoPageBreak(TRUE, '15');
+            // 设置图像比例因子
+            $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
+            if (@file_exists(\Yii::$app->vendorPath . 'tecnickcom/tcpdf/examples/lang/eng.php')) {
+                require_once(\Yii::$app->vendorPath . '/tecnickcom/tcpdf/examples/lang/eng.php');
+                $pdf->setLanguageArray($l);
+            }
+            $pdf->setFontSubsetting(true);
+            $pdf->AddPage();
+            // 设置字体
+            $pdf->SetFont('stsongstdlight', '', 10, '', true);
+            $pdf->writeHTML($context);
+            $pdf->Output($realFile, 'F');
+
+            $this->_updateFirst($realFile, 1);
+        }
+
+        $this->complete();
+        return true;
+    }
+
+    /**
+     * 循环写入数据
+     * @param $realFile
+     * @param $fileNameUpdated
+     * @param int $page
+     * @param int $counter
+     * @return array
+     * @throws Exception
+     */
+    private function _loopWriteDataPDF($realFile, &$fileNameUpdated, $page = 0, $counter = 0){
+        if(method_exists($this->_listModel, 'getList')){
+            $list = $this->_listModel->getList(['condition'=>$this->params['condition'], 'params'=>isset($this->params['params']) ? $this->params['params'] : [], 'others'=>isset($this->params['others']) ? $this->params['others'] : [], 'page'=>$page, 'pageSize'=>$this->pageSize, 'userId'=>$this->userId]);
+        } else {
+            throw new Exception($this->listModelClass.'的getList方法不存在');
+        }
+
+        return $list['list'];
+    }
 }

+ 16 - 4
common/models/BalanceAudit.php

@@ -34,10 +34,10 @@ class BalanceAudit extends \common\components\ActiveRecord
             'name' => 'bonus',
             'label' => '会员账户奖金',
         ],
-        'reconsume_points' => [
-            'name' => 'reconsume_points',
-            'label' => '复消积分',
-        ],
+//        'reconsume_points' => [
+//            'name' => 'reconsume_points',
+//            'label' => '复消积分',
+//        ],
         'exchange_points' => [
             'name' => 'exchange_points',
             'label' => '兑换积分',
@@ -54,6 +54,18 @@ class BalanceAudit extends \common\components\ActiveRecord
 //            'name' => 'lx',
 //            'label' => '领袖分红奖余额',
 //        ],
+        'travel_points' => [
+            'name' => 'travel_points',
+            'label' => '旅游积分',
+        ],
+        'car_points' => [
+            'name' => 'car_points',
+            'label' => '名车积分',
+        ],
+        'house_points' => [
+            'name' => 'house_points',
+            'label' => '豪宅积分',
+        ],
     ];
 
     /**

+ 8 - 2
common/models/CalcBonus.php

@@ -103,6 +103,9 @@ use Yii;
  * @property string $MANAGE_TAX 管理费 
  * @property string $BONUS_BS 蓝星奖金(即新的管理奖)
  * @property string $ORI_BONUS_BS 蓝星原奖金(即新的管理奖,原奖金)
+ * @property string $BONUS_TRAVEL 旅游奖奖金
+ * @property string $BONUS_CAR 名车奖奖金
+ * @property string $BONUS_HOUSE 豪宅奖奖金
  */
 class CalcBonus extends \common\components\ActiveRecord
 {
@@ -122,7 +125,7 @@ class CalcBonus extends \common\components\ActiveRecord
         return [
             [['USER_ID', 'LAST_USER_NAME', 'LAST_REAL_NAME', 'LAST_MOBILE', 'LAST_SYSTEM_ID','LAST_LOCATION', 'PERIOD_NUM', 'CALC_YEAR', 'CALC_MONTH', 'CALCULATED_AT', 'P_CALC_MONTH', 'CREATED_AT'], 'required'],
             [['LAST_STATUS', 'LAST_PERIOD_AT', 'LAST_CREATED_AT', 'LAST_PROVINCE', 'LAST_CITY', 'LAST_COUNTY', 'LAST_IS_DIRECT_SELLER', 'LAST_LOCATION', 'PERIOD_NUM', 'CALC_YEAR', 'CALC_MONTH', 'CALCULATED_AT', 'IS_SENT', 'SENT_AT', 'CREATED_AT'], 'integer'],
-            [['ORI_BONUS_BS','EXCHANGE_POINTS','BONUS_BS','BONUS_QY', 'BONUS_YC', 'BONUS_VIP', 'BONUS_FX', 'BONUS_LS', 'BONUS_FW', 'BONUS_BT', 'BONUS_BT_PROD', 'BONUS_BT_TOOL', 'DEDUCT_ZR', 'BONUS_FL', 'BONUS_CF', 'BONUS_LX', 'SHOULD_QY', 'SHOULD_DEDUCT_ZR', 'PV_1L', 'QY_1L', 'SURPLUS_1L', 'PV_2L', 'QY_2L', 'SURPLUS_2L', 'PV_3L', 'QY_3L', 'SURPLUS_3L', 'PV_4L', 'QY_4L', 'SURPLUS_4L', 'PV_5L', 'QY_5L', 'SURPLUS_5L', 'PV_PCS', 'PV_LS_TOUCH', 'SURPLUS_LS', 'QY_LS', 'PV_TOUCH', 'BONUS_REAL', 'BONUS_TOTAL', 'BONUS_INCOME', 'ORI_BONUS_QY','ORI_BONUS_QY_BD','ORI_BONUS_QY_FX','ORI_BONUS_YC', 'ORI_BONUS_VIP','ORI_BONUS_STANDARD','BONUS_BD','ORI_BONUS_BD','BONUS_TG','ORI_BONUS_TG','BONUS_XF','ORI_BONUS_XF','BONUS_YJ','ORI_BONUS_YJ','ORI_BONUS_YJ_BD','ORI_BONUS_YJ_FX','BONUS_GX','ORI_BONUS_GX','REAL_BONUS_GX','BONUS_GL','ORI_BONUS_GL','REAL_BONUS_GL','ORI_BONUS_GL_BD','ORI_BONUS_GL_FX','RECONSUME_POINTS','MANAGE_TAX'], 'number'],
+            [['ORI_BONUS_BS','EXCHANGE_POINTS','BONUS_BS','BONUS_QY', 'BONUS_YC', 'BONUS_VIP', 'BONUS_FX', 'BONUS_LS', 'BONUS_FW', 'BONUS_BT', 'BONUS_BT_PROD', 'BONUS_BT_TOOL', 'DEDUCT_ZR', 'BONUS_FL', 'BONUS_CF', 'BONUS_LX', 'SHOULD_QY', 'SHOULD_DEDUCT_ZR', 'PV_1L', 'QY_1L', 'SURPLUS_1L', 'PV_2L', 'QY_2L', 'SURPLUS_2L', 'PV_3L', 'QY_3L', 'SURPLUS_3L', 'PV_4L', 'QY_4L', 'SURPLUS_4L', 'PV_5L', 'QY_5L', 'SURPLUS_5L', 'PV_PCS', 'PV_LS_TOUCH', 'SURPLUS_LS', 'QY_LS', 'PV_TOUCH', 'BONUS_REAL', 'BONUS_TOTAL', 'BONUS_INCOME', 'ORI_BONUS_QY','ORI_BONUS_QY_BD','ORI_BONUS_QY_FX','ORI_BONUS_YC', 'ORI_BONUS_VIP','ORI_BONUS_STANDARD','BONUS_BD','ORI_BONUS_BD','BONUS_TG','ORI_BONUS_TG','BONUS_XF','ORI_BONUS_XF','BONUS_YJ','ORI_BONUS_YJ','ORI_BONUS_YJ_BD','ORI_BONUS_YJ_FX','BONUS_GX','ORI_BONUS_GX','REAL_BONUS_GX','BONUS_GL','ORI_BONUS_GL','REAL_BONUS_GL','ORI_BONUS_GL_BD','ORI_BONUS_GL_FX','RECONSUME_POINTS','MANAGE_TAX', 'BONUS_TRAVEL', 'BONUS_CAR', 'BONUS_HOUSE'], 'number'],
             [['ID', 'USER_ID', 'LAST_DEC_LV', 'LAST_EMP_LV', 'LAST_SUB_COM_ID', 'LAST_SYSTEM_ID'], 'string', 'max' => 32],
             [['LAST_USER_NAME', 'LAST_REC_USER_NAME', 'LAST_CON_USER_NAME'], 'string', 'max' => 16],
             [['LAST_REAL_NAME', 'LAST_REC_REAL_NAME', 'LAST_CON_REAL_NAME'], 'string', 'max' => 128],
@@ -237,7 +240,10 @@ class CalcBonus extends \common\components\ActiveRecord
             'BONUS_BS_MNT' => '蓝星管理奖',
             'ORI_BONUS_BS_MNT' => '蓝星管理奖原奖金',
             'BONUS_BS_ABBR' => '蓝星业绩奖',
-            'ORI_BONUS_BS_ABBR' => '蓝星业绩奖原奖金'
+            'ORI_BONUS_BS_ABBR' => '蓝星业绩奖原奖金',
+            'BONUS_TRAVEL' => '旅游奖奖金',
+            'BONUS_CAR' => '名车奖奖金',
+            'BONUS_HOUSE' => '豪宅奖奖金',
         ];
     }
 

+ 9 - 1
common/models/DealType.php

@@ -47,7 +47,15 @@ class DealType extends \common\components\ActiveRecord
     CONST DEDUCT_LOGOUT = 'A1F1E76F34EE4981AB3BF4F8D20BB53E';//注销扣除
     CONST RECONSUME_POINTS_EXCHANGE = 'YA627DTHN81OBO7NIQ1OP8N3PGZX5C66';//复消积分兑换
     CONST EXCHANGE_POINTS_EXCHANGE = '316872011148300288';//兑换积分兑换
-
+    CONST TRAVEL_SEND = '364305038266470400';// 旅游奖奖金发放
+    CONST CAR_SEND = '364305160249413632';// 名车奖奖金发放
+    CONST HOUSE_SEND = '364305230252347392';// 豪宅奖奖金发放
+    CONST TRAVEL_POINTS_EXCHANGE = '365343018452127744'; // 旅游积分兑换
+    CONST CAR_POINTS_EXCHANGE = '365343060634243072'; // 名车积分兑换
+    CONST HOUSE_POINTS_EXCHANGE = '365343108638052352'; // 豪宅积分兑换
+    CONST TRAVEL_POINTS_ADJUST = '365753533326299136'; // 旅游积分余额调整
+    CONST CAR_POINTS_ADJUST = '365753643942678528'; // 名车积分余额调整
+    CONST HOUSE_POINTS_ADJUST = '365753716726435840'; // 豪宅积分余额调整
 
     /**
      * {@inheritdoc}

+ 81 - 0
common/models/FlowZonePoints.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace common\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "{{%FLOW_ZONE_POINTS}}".
+ *
+ * @property string $ID
+ * @property string $USER_ID 会员ID
+ * @property string $CALC_ID 奖金结算表ID
+ * @property string $AMOUNT 金额
+ * @property string $TOTAL 当前总金额
+ * @property int $IS_INCR 是否增加
+ * @property string $REMARK 备注
+ * @property string $ADMIN_NAME 操作人名称
+ * @property int $PERIOD_NUM 所在期数
+ * @property int $CALC_MONTH 所在结算月
+ * @property string $P_MONTH 表分区的日期索引
+ * @property int $CREATED_AT 创建时间
+ * @property int $DELETED 是否删除
+ * @property int $DELETED_AT 删除时间
+ * @property int $SORT 排序
+ * @property string $TRANSFER_SN 转账流水号
+ */
+class FlowZonePoints extends \common\components\ActiveRecord
+{
+    const INCR_REDUCE = 0;      // 减少
+    const INCR_ADD = 1;         // 增加
+    const INCR_FREEZE = 2;      // 冻结
+    const INCR_UNFREEZE = 3;    // 解冻
+
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%FLOW_ZONE_POINTS}}';
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function rules()
+    {
+        return [
+            [['USER_ID', 'REMARK', 'PERIOD_NUM', 'CALC_MONTH', 'P_MONTH', 'CREATED_AT'], 'required'],
+            [['AMOUNT', 'TOTAL'], 'number'],
+            [['IS_INCR', 'PERIOD_NUM', 'CALC_MONTH', 'CREATED_AT', 'DELETED', 'DELETED_AT', 'SORT'], 'integer'],
+            [['ID', 'USER_ID', 'CALC_ID', 'ADMIN_NAME', 'TRANSFER_SN'], 'string', 'max' => 32],
+            [['REMARK'], 'string', 'max' => 255],
+            [['ID'], 'unique'],
+        ];
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function attributeLabels()
+    {
+        return [
+            'ID' => 'ID',
+            'USER_ID' => '会员ID',
+            'CALC_ID' => '结算表ID',
+            'AMOUNT' => '交易金额',
+            'TOTAL' => '当前总金额',
+            'IS_INCR' => '是否增加',
+            'REMARK' => '备注',
+            'ADMIN_NAME' => '操作人名称',
+            'PERIOD_NUM' => '所在期数',
+            'CALC_MONTH' => '所在结算月',
+            'P_MONTH' => '表分区的日期索引',
+            'CREATED_AT' => '创建时间',
+            'DELETED' => '是否删除',
+            'DELETED_AT' => '删除时间',
+            'SORT' => '排序',
+            'TRANSFER_SN' => '转账流水号',
+        ];
+    }
+}

+ 6 - 2
common/models/OrderGoods.php

@@ -19,6 +19,8 @@ use Yii;
  * @property string $SKU_CODE 商品编码
  * @property int $BUY_NUMS 购买数量
  * @property string $P_CALC_MONTH 分区日期
+ * @property int CATEGORY_TYPE 商品分类
+ * @property int PAY_TYPE 支付方式
  */
 class OrderGoods extends \common\components\ActiveRecord
 {
@@ -36,8 +38,8 @@ class OrderGoods extends \common\components\ActiveRecord
     public function rules()
     {
         return [
-            [['ORDER_SN', 'GOODS_ID', 'GOODS_TITLE', 'SKU_CODE'], 'required'],
-            [['PRICE', 'REAL_PRICE', 'PV', 'REAL_PV', 'POINT'], 'number'],
+            [['ORDER_SN', 'GOODS_ID', 'GOODS_TITLE', 'SKU_CODE', 'CATEGORY_TYPE', 'PAY_TYPE'], 'required'],
+            [['PRICE', 'REAL_PRICE', 'PV', 'REAL_PV', 'POINT', 'CATEGORY_TYPE', 'PAY_TYPE'], 'number'],
             [['BUY_NUMS'], 'integer'],
             [['ID', 'ORDER_SN', 'GOODS_ID'], 'string', 'max' => 32],
             [['GOODS_TITLE'], 'string', 'max' => 255],
@@ -64,6 +66,8 @@ class OrderGoods extends \common\components\ActiveRecord
             'SKU_CODE' => '商品编码',
             'BUY_NUMS' => '购买数量',
             'P_CALC_MONTH' => '分区日期',
+            'CATEGORY_TYPE' => '商品分类',
+            'PAY_TYPE' => '支付方式',
         ];
     }
 }

+ 70 - 9
common/models/ShopGoods.php

@@ -10,6 +10,7 @@ namespace common\models;
  * @property string $CATE_ID 所属分类ID
  * @property string $TYPE 商品来源
  * @property string $GIFT_TYPE 商品类型
+ * @property string $CATEGORY_TYPE 商品分类
  * @property string $SELL_TYPE 允许购买方式
  * @property int $GOODS_NO 商品编号
  * @property string $UNIT 单位
@@ -32,14 +33,34 @@ class ShopGoods extends \common\components\ActiveRecord
 {
     const SALE_TYPE = [
         1 => [
+            'id' => 1,
             'name' => '余额购买',
+            'label' => 'cash',
         ],
-        2 => [
-            'name' => '复消兑换',
-        ],
+//        2 => [
+//            'id' => 2,
+//            'name' => '复消兑换',
+//        ],
         3 => [
-            'name' => '积分兑换'
-        ]
+            'id' => 3,
+            'name' => '兑换点数',
+            'label' => 'exchange',
+        ],
+        4 => [
+            'id' => 4,
+            'name' => '旅游积分',
+            'label' => 'travel_points',
+        ],
+        5 => [
+            'id' => 5,
+            'name' => '名车积分',
+            'label' => 'car_points',
+        ],
+        6 => [
+            'id' => 6,
+            'name' => '豪宅积分',
+            'label' => 'house_points',
+        ],
     ];
     const GOODS_TYPE = [
         1 =>[
@@ -69,6 +90,36 @@ class ShopGoods extends \common\components\ActiveRecord
         1 => '已上架',
         0 => '已下架',
     ];
+    const CATEGORY_TYPE = [
+        [
+            'id' => 1,
+            'name' => '普通商品',
+            'sell_type' => [
+                self::SALE_TYPE[1],
+                self::SALE_TYPE[3]]
+            ],
+        [
+            'id' => 4,
+            'name' => '旅游积分商品',
+            'sell_type' => [
+                self::SALE_TYPE[4]
+            ]
+        ],
+        [
+            'id' => 5,
+            'name' => '名车积分商品',
+            'sell_type' => [
+                self::SALE_TYPE[5]
+            ]
+        ],
+        [
+            'id' => 6,
+            'name' => '豪宅积分商品',
+            'sell_type' => [
+                self::SALE_TYPE[6]
+            ]
+        ],
+    ];
     /**
      * @inheritdoc
      */
@@ -83,10 +134,10 @@ class ShopGoods extends \common\components\ActiveRecord
     public function rules()
     {
         return [
-            [['SELL_DISCOUNT','GOODS_NAME', 'CATE_ID','GIFT_TYPE', 'GOODS_NO', 'SELL_PRICE','MARKET_PRICE','PRICE_PV','STORE_NUMS'], 'required'],
+            [['SELL_DISCOUNT','GOODS_NAME', 'CATE_ID','GIFT_TYPE', 'GOODS_NO', 'SELL_PRICE','MARKET_PRICE','PRICE_PV','STORE_NUMS', 'SELL_TYPE', 'CATEGORY_TYPE'], 'required'],
             [['STORE_NUMS'], 'integer'],
-            [['SELL_PRICE','MARKET_PRICE','PRICE_PV','POINT'], 'number'],
-            [['ID','CATE_ID', 'GOODS_NO','SELL_TYPE','GIFT_TYPE'], 'string', 'max' => 32],
+            [['SELL_PRICE','MARKET_PRICE','PRICE_PV','POINT', 'SELL_TYPE', 'CATEGORY_TYPE'], 'number'],
+            [['ID','CATE_ID', 'GOODS_NO','GIFT_TYPE'], 'string', 'max' => 32],
             [['UNIT'], 'string', 'max' => 16],
             [['COVER', 'GOODS_NAME'], 'string', 'max' => 255],
             [['IMAGES','CONTENT'], 'string', 'max' => 4000],
@@ -107,6 +158,7 @@ class ShopGoods extends \common\components\ActiveRecord
             // 'TYPE' => '商品来源',
             'SELL_DISCOUNT' => '会员折扣',
             'GIFT_TYPE' => '商品类型',
+            'CATEGORY_TYPE' => '商品分类',
             'SELL_TYPE' => '出售方式',
             'GOODS_NO' => '商品编号',
             'UNIT' => '商品单位',
@@ -167,7 +219,16 @@ class ShopGoods extends \common\components\ActiveRecord
                 'name'=>'积分支付'
             ],
             'exchange' => [
-                'name' => '无业绩兑换券'
+                'name' => '积分点数'
+            ],
+            'travel_points'=>[
+                'name'=>'旅游积分'
+            ],
+            'car_points'=>[
+                'name'=>'名车积分'
+            ],
+            'house_points' => [
+                'name' => '豪宅积分'
             ]
         ];
     }

+ 8 - 2
common/models/UserBonus.php

@@ -68,7 +68,7 @@ class UserBonus extends \common\components\ActiveRecord
     {
         return [
             [['USER_ID', 'CREATED_AT'], 'required'],
-            [['BS_TOTAL','ORI_BS_TOTAL','BS','BONUS', 'BONUS_FREEZE', 'CF', 'LX', 'QY_TOTAL', 'YC_TOTAL', 'VIP_TOTAL', 'FX_TOTAL', 'LS_TOTAL', 'FW_TOTAL', 'BT_TOTAL', 'BT_PROD_TOTAL', 'BT_TOOL_TOTAL', 'CF_TOTAL', 'LX_TOTAL', 'DEDUCT_ZR_TOTAL', 'FL_TOTAL', 'BD_TOTAL','TG_TOTAL','YJ_TOTAL','GX_TOTAL','GL_TOTAL', 'ORI_QY_TOTAL','ORI_YC_TOTAL','ORI_YC_TOTAL','ORI_BD_TOTAL','ORI_TG_TOTAL','ORI_YJ_TOTAL','ORI_GX_TOTAL','ORI_GL_TOTAL','RECONSUME_POINTS','MANAGE_TAX', 'RECONSUME_POINTS_EXPIRED', 'RECONSUME_POINTS_TOTAL', 'BONUS_TOTAL'], 'number'],
+            [['BS_TOTAL','ORI_BS_TOTAL','BS','BONUS', 'BONUS_FREEZE', 'CF', 'LX', 'QY_TOTAL', 'YC_TOTAL', 'VIP_TOTAL', 'FX_TOTAL', 'LS_TOTAL', 'FW_TOTAL', 'BT_TOTAL', 'BT_PROD_TOTAL', 'BT_TOOL_TOTAL', 'CF_TOTAL', 'LX_TOTAL', 'DEDUCT_ZR_TOTAL', 'FL_TOTAL', 'BD_TOTAL','TG_TOTAL','YJ_TOTAL','GX_TOTAL','GL_TOTAL', 'ORI_QY_TOTAL','ORI_YC_TOTAL','ORI_YC_TOTAL','ORI_BD_TOTAL','ORI_TG_TOTAL','ORI_YJ_TOTAL','ORI_GX_TOTAL','ORI_GL_TOTAL','RECONSUME_POINTS','MANAGE_TAX', 'RECONSUME_POINTS_EXPIRED', 'RECONSUME_POINTS_TOTAL', 'BONUS_TOTAL', 'TRAVEL_POINTS', 'CAR_POINTS', 'HOUSE_POINTS'], 'number'],
             [['VER', 'CREATED_AT'], 'integer'],
             [['ID','USER_ID'], 'string', 'max' => 32],
             [['USER_ID'], 'unique'],
@@ -122,7 +122,13 @@ class UserBonus extends \common\components\ActiveRecord
             'BONUS_TOTAL' => '总奖金累计',
             'BS' => '蓝星奖(即新的管理奖)',
             'BS_TOTAL' => '蓝星(管理)累计',
-            'ORI_BS_TOTAL' => '蓝星原奖金累计'
+            'ORI_BS_TOTAL' => '蓝星原奖金累计',
+            'TRAVEL' => '旅游积分',
+            'TRAVEL_TOTAL' => '旅游积分累计',
+            'CAR' => '名车积分',
+            'CAR_TOTAL' => '名车积分累计',
+            'HOUSE' => '豪宅积分',
+            'HOUSE_TOTAL' => '豪宅积分累计',
         ];
     }
 

+ 15 - 3
common/models/forms/ConfigPeriodForm.php

@@ -17,6 +17,7 @@ class ConfigPeriodForm extends Model
     public $calcYear;
     public $closeWeekDate;
     public $closeTime;
+    public $closeDays;
 
     public function init() {
         parent::init();
@@ -31,10 +32,11 @@ class ConfigPeriodForm extends Model
     public function rules()
     {
         return [
-            [['calcYear', 'closeWeekDate', 'closeTime'], 'required'],
+            [['calcYear', 'closeWeekDate', 'closeTime', 'closeDays'], 'required'],
             [['calcYear'], 'integer', 'max'=>2050, 'min'=>2018],
             [['closeWeekDate'], 'match', 'pattern' => '/^[0-6]/', 'message' => '请填写有效的星期'],
             [['closeTime'], 'time', 'format'=>'HH:mm'],
+            [['closeDays'], 'match', 'pattern' => '/^[1-4]/', 'message' => '请填写有效的天数'],
         ];
     }
 
@@ -44,6 +46,7 @@ class ConfigPeriodForm extends Model
             'calcYear' => '计算至年份',
             'closeWeekDate' => '封期日期',
             'closeTime' => '封期时间',
+            'closeDays' => '封期周期天数',
         ];
     }
 
@@ -75,10 +78,13 @@ class ConfigPeriodForm extends Model
             if(!Config::updateAll(['VALUE'=>$this->closeTime, 'UPDATED_AT'=>Date::nowTime()], "CONFIG_NAME='closeTime'")){
                 throw new Exception('封期时间更新失败');
             }
+            if(!Config::updateAll(['VALUE'=>$this->closeDays, 'UPDATED_AT'=>Date::nowTime()], "CONFIG_NAME='closeDays'")){
+                throw new Exception('封期天数更新失败');
+            }
             // 异步重新生成业绩期先注释掉
             // 异步处理添加任务
-            //$taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('config/update-period', \Yii::$app->request->post());
-            $taskKey = true;
+            $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('config/update-period', \Yii::$app->request->post());
+//            $taskKey = true;
             if($taskKey === false){
                 throw new Exception('请求异步服务器失败');
             }
@@ -120,8 +126,14 @@ class ConfigPeriodForm extends Model
         $startDateTemp = $nowPeriodStart;
         $transaction = \Yii::$app->db->beginTransaction();
         try{
+            $days = 1;
             for($startDate = $nowPeriodStart + 86400; $startDate < strtotime($this->calcYear.'-12-31'); $startDate += 86400 ){
                 if(Date::dateWeek(\date('Y-m-d',$startDate)) == $this->closeWeekDate){
+                    $days++;
+                    if ($days % $this->closeDays != 0) {
+                        continue;
+                    }
+
                     $periodModel = new Period();
                     $periodModel->PERIOD_NUM = $nowPeriodNum;
                     $periodModel->START_TIME = $startDateTemp;

+ 31 - 20
common/models/forms/DeclarationForm.php

@@ -783,9 +783,13 @@ class DeclarationForm extends Model
         }
 
         // 加入订单信息
-        $warehouse = Region::getWarehouseByCode($this->province);//仓库
-        if(!$warehouse){
-            throw new Exception('地区暂时不支持配送,具体联系客服');
+        if($this->province!=1){
+            $warehouse = Region::getWarehouseByCode($this->province);//仓库
+            if(!$warehouse){
+                throw new Exception('地区暂时不支持配送,具体联系客服');
+            }
+        }else{
+            $warehouse = '01';
         }
         $orderModel = new Order();
         $orderModel->SN = 'OS'.$ord;
@@ -813,6 +817,9 @@ class DeclarationForm extends Model
         $orderModel->STATUS = 1;
         $orderModel->CREATED_AT = Date::nowTime();
         $orderModel->CREATE_USER = Info::getUserNameByUserId(\Yii::$app->user->id);
+        if($this->province==1){
+            $orderModel->EXPRESS_TYPE = 1;
+        }
         if(!$orderModel->save()){
             throw new Exception(Form::formatErrorsForApi($orderModel->getErrors()));
         }
@@ -823,24 +830,28 @@ class DeclarationForm extends Model
         }
         OrderGoods::batchInsert($this->_orderGoods);
 
-        //写入收货地址信息
-        $addressModel = new ReceiveAddress();
-        $addressModel->USER_ID = $this->_insertUserId;
-        $addressModel->USER_NAME = $this->insertUserName;
-        $addressModel->CONSIGNEE = $this->consignee;
-        $addressModel->MOBILE = $this->acceptMobile;
-        $addressModel->PROVINCE = $this->province;
-        $addressModel->CITY = $this->city;
-        $addressModel->COUNTY = intval($this->county) ?? 0;
-        $addressModel->ADDRESS = $this->address;
-        $addressModel->IS_DEFAULT = 1;
-        if(!$addressModel->save()){
-            throw new Exception(Form::formatErrorsForApi($addressModel->getErrors()));
+        //写入收货地址信息,判断province字段,当不为1时,插入收货地址信息
+        if($this->province!=1){
+            $addressModel = new ReceiveAddress();
+            $addressModel->USER_ID = $this->_insertUserId;
+            $addressModel->USER_NAME = $this->insertUserName;
+            $addressModel->CONSIGNEE = $this->consignee;
+            $addressModel->MOBILE = $this->acceptMobile;
+            $addressModel->PROVINCE = $this->province;
+            $addressModel->CITY = $this->city;
+            $addressModel->COUNTY = intval($this->county) ?? 0;
+            $addressModel->ADDRESS = $this->address;
+            $addressModel->IS_DEFAULT = 1;
+            if(!$addressModel->save()){
+                throw new Exception(Form::formatErrorsForApi($addressModel->getErrors()));
+            }
+            //扣报单人现金钱包
+            Cash::changeUserCash(\Yii::$app->user->id, 'CASH', -abs($this->_decAmount), ['REMARK' =>'为'.$this->insertUserName.'报单']);
+            return $addressModel;
+        }else{
+            $addressModel = new ReceiveAddress();
+            return $addressModel;
         }
-        //扣报单人现金钱包
-        Cash::changeUserCash(\Yii::$app->user->id, 'CASH', -abs($this->_decAmount), ['REMARK' =>'为'.$this->insertUserName.'报单']);
-
-        return $addressModel;
     }
 
 

+ 115 - 26
common/models/forms/OrderForm.php

@@ -184,7 +184,37 @@ class OrderForm extends Model
      */
     public function isPayType($attribute){
         if(!array_key_exists($this->payType, ShopGoods::payTypes())){
-            $this->addError($attribute, '支付方式错误');
+            $this->addError($attribute, '支付方式错误1');
+            return;
+        }
+
+        // 一个订单只能包含一类商品
+        $goods = ShopGoods::find()->select('ID,CATEGORY_TYPE')->where(['in', 'ID', $this->goodsId])->andWhere(['STATUS' => 1])->asArray()->all();
+        $goodsCategoryType = array_unique(array_column($goods, 'CATEGORY_TYPE'));
+        if (count($goodsCategoryType) != 1) {
+            $this->addError($attribute, '订单不能包含多种商品分类');
+            return;
+        }
+
+        // 购买方式
+        $sellTypeLabelMap = array_column(ShopGoods::SALE_TYPE, NULL, 'label');
+        if (!array_key_exists($this->payType, $sellTypeLabelMap)) {
+            $this->addError($attribute, '支付方式错误2');
+            return;
+        }
+
+        // 所选支付方式必须是商品分类支持的类型
+        $categoryType = array_column(ShopGoods::CATEGORY_TYPE, NULL, 'id');
+        // 商品类型
+        $currCategoryType = $goodsCategoryType[0];
+        if (!array_key_exists($currCategoryType, $categoryType)) {
+            $this->addError($attribute, '商品分类错误');
+            return;
+        }
+
+        $sellType = $categoryType[$currCategoryType]['sell_type'] ?? [];
+        if (!$sellType || !in_array($this->payType, array_column($sellType, 'label'))) {
+            $this->addError($attribute, '支付方式错误3');
             return;
         }
     }
@@ -320,7 +350,9 @@ class OrderForm extends Model
                         'POINT' => $goods['POINT'],
                         'BUY_NUMS' => intval($v),
                         'SKU_CODE' => $goods['GOODS_NO'],
-                        'GOODS_TITLE' => $goods['GOODS_NAME']
+                        'GOODS_TITLE' => $goods['GOODS_NAME'],
+                        'CATEGORY_TYPE' => $goods['CATEGORY_TYPE'],
+                        'PAY_TYPE' => $this->payType,
                     ];
                 }
             }
@@ -328,42 +360,69 @@ class OrderForm extends Model
         $this->_decAmount = $totalAmount;
         $this->_decPv = $totalPv;
         $this->_freight = ($totalAmount>=300) ? 0 : 15;
+        if($this->_address['PROVINCE']==1){
+            $this->_freight = 0;
+        }
         $this->_payAmount = $this->_decAmount + $this->_freight;
 
-
         $db = \Yii::$app->db;
         $transaction = $db->beginTransaction();
         try {
             //判断用户余额是否充足
-            $loginUserId = \Yii::$app->user->id;
-            if($this->payType=='cash') {
-                if (Cash::getAvailableBalance($loginUserId) < $this->_payAmount) {
-                    throw new Exception('余额不足,无法购买商品');
-                }
-            } else if ($this->payType =='exchange') {
-                if ($this->_payAmount > Balance::getBalanceExchangePoints($loginUserId)) {
-                    throw new Exception('兑换积分不足,无法购买商品');
-                }
-            } else{
-                if ($this->_payAmount > Balance::getBalanceReconsumePoints($loginUserId)) {
-                    throw new Exception('复消积分不足,无法购买商品');
-                }
+            $result = $this->getBalanceAdequate($this->payType, $this->_payAmount);
+            if ($result['code'] !== 200) {
+                throw new Exception($result['message']);
             }
+
             //写入订单
             if (!$orderResult = $this->addOrder()) {
                 throw new Exception(Form::formatErrorsForApi($orderResult->getErrors()));
             }
+
             $transaction->commit();
         }catch (\Exception $e){
             $transaction->rollBack();
             $this->addError('add', $e->getMessage());
             return null;
         }
+
         return true;
     }
 
+    /**
+     * 判断对应账户余额是否充足.
+     * @param $payType string 支付方式.
+     * @param $payAmount numeric 支付金额
+     * @return array|int[]
+     */
+    public function getBalanceAdequate(string $payType, $payAmount): array
+    {
+        $loginUserId = \Yii::$app->user->id;
+
+        if ($payType == 'cash') {
+            if (Cash::getAvailableBalance($loginUserId) < $payAmount) {
+                return ['code' => 500, 'message' => '余额不足,无法购买商品'];
+            }
+        } else if ($payType =='exchange') {
+            if ($payAmount > Balance::getBalanceExchangePoints($loginUserId)) {
+                return ['code' => 500, 'message' => '兑换积分不足,无法购买商品'];
+            }
+        } else if (in_array($payType, ['travel_points', 'car_points', 'house_points'])) {
+            if ($payAmount > Balance::getAccountBalance($loginUserId, $payType)) {
+                return ['code' => 500, 'message' => (Balance::BALANCE_TYPE[$payType]['title'] ?? '积分') . '不足,无法购买商品'];
+            }
+        } else{
+            if ($payAmount > Balance::getBalanceReconsumePoints($loginUserId)) {
+                return ['code' => 500, 'message' => '复消积分不足,无法购买商品'];
+            }
+        }
+
+        return ['code' => 200];
+    }
+
     /**
      * 复销订单
+     * @throws Exception
      */
     public function addOrder(){
         $periodObj = Period::instance();
@@ -371,13 +430,21 @@ class OrderForm extends Model
         $nowCalcMonth = $periodObj->getYearMonth($nowPeriodNum);
 
         $userId = \Yii::$app->user->id;
-        $userName = Info::getUserNameByUserId($userId);
 
+        $userName = Info::getUserNameByUserId($userId);
+        $userRealName = Info::getUserRealNameByUserId($userId);
+        $userMobile = Info::getUserMobileByUserId($userId);
         // 加入订单信息
-        $warehouse = Region::getWarehouseByCode($this->_address['PROVINCE']);//仓库
-        if(!$warehouse){
-            throw new Exception('地区暂时不支持配送,具体联系客服');
+        if ($this->_address['PROVINCE'] != 1) {
+            $warehouse = Region::getWarehouseByCode($this->_address['PROVINCE']);//仓库
+            if (!$warehouse) {
+                throw new Exception('地区2暂时不支持配送,具体联系客服');
+            }
+        }else{
+            $warehouse = '01';
         }
+        $_hasPV = in_array($this->payType, ['exchange', 'travel_points', 'car_points', 'house_points']) ? 0 : $this->_decPv;
+
         $ordNo = $this->_generateSn();
         $orderModel = new Order();
         $orderModel->SN = 'OS'.$ordNo;
@@ -386,9 +453,9 @@ class OrderForm extends Model
         $orderModel->USER_ID = $userId;
         $orderModel->USER_NAME = $userName;
         $orderModel->ORDER_AMOUNT = $this->_decAmount;
-        $orderModel->PV = $this->payType =='exchange' ? 0 : $this->_decPv;
+        $orderModel->PV = $_hasPV;
         $orderModel->PAY_AMOUNT = $this->_payAmount;
-        $orderModel->PAY_PV = $this->payType =='exchange' ? 0 : $this->_decPv; // 兑换积分不能算业绩
+        $orderModel->PAY_PV = $_hasPV; // 兑换积分不能算业绩
         $orderModel->PAY_AT = Date::nowTime();
         $orderModel->PAY_TYPE = $this->payType;
         $orderModel->PERIOD_NUM = $nowPeriodNum;
@@ -406,6 +473,15 @@ class OrderForm extends Model
         $orderModel->STATUS = 1;
         $orderModel->CREATED_AT = Date::nowTime();
         $orderModel->CREATE_USER = $userName;
+        if($this->_address['PROVINCE']==1){
+            $orderModel->EXPRESS_TYPE = 1;
+            $orderModel->CONSIGNEE = $userRealName;
+            $orderModel->MOBILE = $userMobile;
+            $orderModel->PROVINCE = 1;
+            $orderModel->CITY = 1;
+            $orderModel->COUNTY = 1;
+            $orderModel->ADDRESS = '';
+        }
         if(!$orderModel->save()){
             $this->addErrors($orderModel->getErrors());
             return false;
@@ -413,7 +489,7 @@ class OrderForm extends Model
         // 加入商品到订单商品表
         foreach($this->_orderGoods as $key=>$value){
             // 增加判断,如果订单是兑换券购买,则AR_ORDER_GOODS中的REAL_PV真实PV应该是0
-            if ($orderModel->PAY_TYPE == 'exchange') {
+            if (in_array($orderModel->PAY_TYPE, ['exchange', 'travel_points', 'car_points', 'house_points'])) {
                 $this->_orderGoods[$key]['REAL_PV'] = 0;
             }
             $this->_orderGoods[$key]['ORDER_SN'] = $orderModel->SN;
@@ -426,6 +502,12 @@ class OrderForm extends Model
             Cash::changeUserCash(\Yii::$app->user->id, 'CASH', -abs($this->_payAmount), ['REMARK' => '会员复销余额支付']);
         } else if ($this->payType=='exchange') {
             Balance::changeUserBonus(\Yii::$app->user->id,'exchange_points', -abs($this->_payAmount),['DEAL_TYPE_ID' => DealType::EXCHANGE_POINTS_EXCHANGE,'REMARK' => '会员兑换积分兑换']);
+        } else if ($this->payType == 'travel_points') {
+            Balance::changeUserBonus(\Yii::$app->user->id, 'travel_points', -abs($this->_payAmount), ['DEAL_TYPE_ID' => DealType::TRAVEL_POINTS_EXCHANGE,'REMARK' => '会员旅游换积分兑换']);
+        } else if ($this->payType == 'car_points') {
+            Balance::changeUserBonus(\Yii::$app->user->id, 'car_points', -abs($this->_payAmount), ['DEAL_TYPE_ID' => DealType::CAR_POINTS_EXCHANGE,'REMARK' => '会员名车积分兑换']);
+        } else if ($this->payType == 'house_points') {
+            Balance::changeUserBonus(\Yii::$app->user->id, 'house_points', -abs($this->_payAmount), ['DEAL_TYPE_ID' => DealType::HOUSE_POINTS_EXCHANGE,'REMARK' => '会员豪宅积分兑换']);
         } else{
             Balance::changeUserBonus(\Yii::$app->user->id,'reconsume_points', -abs($this->_payAmount),['DEAL_TYPE_ID' => DealType::RECONSUME_POINTS_EXCHANGE,'REMARK' => '会员复销积分兑换']);
         }
@@ -478,6 +560,9 @@ class OrderForm extends Model
         $this->_decAmount = $totalAmount;
         $this->_decPv = $totalPv;
         $this->_freight = ($totalAmount>=300) ? 0 : 15;
+        if($this->_address['PROVINCE']==1){
+            $this->_freight = 0;
+        }
         $this->_payAmount = $this->_decAmount + $this->_freight;
 
         $db = \Yii::$app->db;
@@ -531,9 +616,13 @@ class OrderForm extends Model
         $userId = Info::getUserIdByUserName($this->userName);
 
         // 加入订单信息
-        $warehouse = Region::getWarehouseByCode($this->province);//仓库
-        if(!$warehouse){
-            throw new Exception('地区暂时不支持配送,具体联系客服');
+        if($this->province!=1){
+            $warehouse = Region::getWarehouseByCode($this->province);//仓库
+            if(!$warehouse){
+                throw new Exception('地区1暂时不支持配送,具体联系客服');
+            }
+        }else{
+            $warehouse = '01';
         }
         $ordNo = $this->_generateSn();
         $orderModel = new Order();

+ 41 - 6
common/models/forms/ShopGoodsForm.php

@@ -31,6 +31,7 @@ class ShopGoodsForm extends Model
     public $content;
     public $sort;
     public $status;
+    public $categoryType;
 
     private $_model;
 
@@ -48,14 +49,14 @@ class ShopGoodsForm extends Model
     {
         return [
             [['id','sellDiscount','giftType','sellType','goodsNo', 'goodsName', 'unit', 'sellPrice', 'marketPrice', 'pricePv', 'storeNums', 'content', 'sort','status','cover'], 'trim'],
-            [['goodsName','sellDiscount','giftType','goodsNo', 'storeNums','sellPrice','marketPrice','pricePv', 'sort','status','cover'], 'required'],
+            [['goodsName','sellDiscount','giftType','goodsNo', 'storeNums','sellPrice','marketPrice','pricePv', 'sort','status','cover', 'categoryType'], 'required'],
             [['id'], 'required', 'on'=>'edit'],
             [['id'], 'exist', 'targetClass'=>ShopGoods::class, 'targetAttribute'=>'ID'],
             [['sellPrice','marketPrice','pricePv'], 'price'],
             [['id'], 'initModel'],
             [['selectedIds'], 'isSelected'],
             [['sort'], 'isSort'],
-            [['sellDiscount'], 'isDiscount']
+            [['sellDiscount'], 'isDiscount'],
         ];
     }
 
@@ -67,6 +68,7 @@ class ShopGoodsForm extends Model
             'goodsName' => '商品名称',
             'sellDiscount' => '会员折扣',
             'giftType' => '商品类型',
+            'categoryType' => '商品分类',
             'sellType' => '出售方式',
             'goodsNo' => '产品编号',
             'unit' => '单位',
@@ -89,8 +91,8 @@ class ShopGoodsForm extends Model
     {
         $parentScenarios =  parent::scenarios();
         $customScenarios = [
-            'add' => ['goodsName','sellDiscount','giftType', 'sellType','goodsNo','unit','sellPrice','marketPrice','pricePv','storeNums', 'content','sort','cover'],
-            'edit' => ['id','goodsName','sellDiscount','giftType', 'sellType','goodsNo','unit','sellPrice','marketPrice','pricePv', 'storeNums', 'content','sort','cover'],
+            'add' => ['goodsName','sellDiscount','giftType', 'sellType','goodsNo','unit','sellPrice','marketPrice','pricePv','storeNums', 'content','sort','cover', 'categoryType'],
+            'edit' => ['id','goodsName','sellDiscount','giftType', 'sellType','goodsNo','unit','sellPrice','marketPrice','pricePv', 'storeNums', 'content','sort','cover', 'categoryType'],
             'changeStatus' => ['selectedIds', 'status'],
         ];
         return array_merge($parentScenarios, $customScenarios);
@@ -106,6 +108,37 @@ class ShopGoodsForm extends Model
             $this->addError($attributes, '数据不存在');
         }
     }
+
+    /**
+     * 前置数据填充和校验.
+     * @return bool
+     */
+    public function beforeValidate()
+    {
+        // 处理sellType
+        $categoryType = array_column(ShopGoods::CATEGORY_TYPE, NULL, 'id');
+        $sellType = $categoryType[$this->categoryType]['sell_type'] ?? [];
+        if (!$sellType) {
+            $this->addError('add', '商品购买方式错误');
+        } else {
+            foreach ($sellType as $item) {
+                if (!in_array($item['id'], array_keys(ShopGoods::SALE_TYPE))) {
+                    $this->addError('add', '商品购买方式错误');
+                    break;
+                }
+            }
+
+            // 购买方式格式化为','分割的方式
+            $sellType = implode(',', array_column($sellType, 'id'));
+            // 如果是普通商品,有PV,旅游、名车、豪宅商品没有PV
+            if ($this->categoryType != 1) {
+                $this->pricePv = 0;
+            }
+        }
+
+        return parent::beforeValidate();
+    }
+
     /**
      * 批量数据
      * @param $attributes
@@ -153,7 +186,7 @@ class ShopGoodsForm extends Model
             $shopGoods->SELL_DISCOUNT = $this->sellDiscount;
             $shopGoods->GIFT_TYPE = implode(',',$this->giftType);
             // $shopGoods->SELL_TYPE = implode(',',$this->sellType);
-            $shopGoods->SELL_TYPE = '1,2,3';
+            $shopGoods->SELL_TYPE = $this->sellType;
             $shopGoods->GOODS_NO = $this->goodsNo;
             $shopGoods->UNIT = $this->unit ? $this->unit : '个';
             $shopGoods->COVER = $this->cover ? $this->cover : '';
@@ -166,6 +199,7 @@ class ShopGoodsForm extends Model
             $shopGoods->SORT = $this->sort;
             $shopGoods->CATE_ID = '1';
             $shopGoods->CREATED_AT = Date::nowTime();
+            $shopGoods->CATEGORY_TYPE = $this->categoryType;
             if (!$shopGoods->save()) {
                 throw new Exception(Form::formatErrorsForApi($shopGoods->getErrors()));
             }
@@ -197,7 +231,7 @@ class ShopGoodsForm extends Model
             $model->SELL_DISCOUNT = $this->sellDiscount;
             $model->GIFT_TYPE = implode(',',$this->giftType);
             // $model->SELL_TYPE = implode(',',$this->sellType);
-            $model->SELL_TYPE = '1,2,3';
+            $model->SELL_TYPE = $this->sellType;
             $model->GOODS_NO = $this->goodsNo;
             $model->UNIT = $this->unit ? $this->unit : '个';
             $model->COVER = $this->cover ? $this->cover : '';
@@ -209,6 +243,7 @@ class ShopGoodsForm extends Model
             $model->STORE_NUMS = $this->storeNums;
             $model->SORT = $this->sort;
             $model->UPDATED_AT = Date::nowTime();
+            $model->CATEGORY_TYPE = $this->categoryType;
             if (!$model->save()) {
                 throw new Exception(Form::formatErrorsForApi($model->getErrors()));
             }

+ 6 - 2
composer.json

@@ -26,7 +26,8 @@
         "yiisoft/yii2-redis": "^2.0",
         "ext-pdo": "*",
         "ext-json": "*",
-        "monolog/monolog": "^2.4"
+        "monolog/monolog": "^2.4",
+        "tecnickcom/tcpdf": "^6.4"
     },
     "require-dev": {
         "yiisoft/yii2-debug": "~2.0.0",
@@ -45,7 +46,10 @@
         }
     },
     "autoload": {
-        "files": ["common/helpers/LoggerTool.php"]
+        "files": [
+            "common/helpers/LoggerTool.php",
+            "common/helpers/Constant.php"
+        ]
     },
     "repositories": {
         "packagist": {

+ 48 - 0
console/controllers/ShopController.php

@@ -82,4 +82,52 @@ class ShopController extends BaseController
         unset($factory);
         return false;
     }
+
+    /**
+     * 订单列表导出PDF
+     * @param $taskId
+     * @return bool
+     */
+    public function actionOrderListExportPdf($taskId)
+    {
+        $factory = ShopExport::factory($taskId);
+        $factory->listModelClass = OrderList::class;
+        try {
+            if ($factory->generatePDF()) {
+                Yii::$app->swooleAsyncTimer->pushAsyncResultToAdmin($factory->getUserId(), '订单列表导出成功');
+            }
+            unset($factory);
+            return true;
+        } catch (\Exception $e) {
+            echo '订单列表导出失败。详情:' . $e->getMessage();
+            Yii::$app->swooleAsyncTimer->pushAsyncResultToAdmin($factory->getUserId(), '订单列表导出失败。详情:' . $e->getMessage(), false);
+        }
+
+        unset($factory);
+        return false;
+    }
+
+    /**
+     * 订单列表导出PDF
+     * @param $taskId
+     * @return bool
+     */
+    public function actionDecOrderListExportPdf($taskId)
+    {
+        $factory = ShopExport::factory($taskId);
+        $factory->listModelClass = OrderList::class;
+        try {
+            if ($factory->generatePDF()) {
+                Yii::$app->swooleAsyncTimer->pushAsyncResultToAdmin($factory->getUserId(), '订单列表导出成功');
+            }
+            unset($factory);
+            return true;
+        } catch (\Exception $e) {
+            echo '订单列表导出失败。详情:' . $e->getMessage();
+            Yii::$app->swooleAsyncTimer->pushAsyncResultToAdmin($factory->getUserId(), '订单列表导出失败。详情:' . $e->getMessage(), false);
+        }
+
+        unset($factory);
+        return false;
+    }
 }

+ 1 - 1
frontendApi/config/menu.php

@@ -73,7 +73,7 @@ return [
         'show'=>1,
         'child'=>[
             ['name'=>'我的账户', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'index', 'routePath'=>'bonus/index', 'show'=>1,],
-            ['name'=>'最新奖金', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'new', 'routePath'=>'bonus/new', 'show'=>1,'allow'=>'newBonusSwitch'],
+//            ['name'=>'最新奖金', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'new', 'routePath'=>'bonus/new', 'show'=>1,'allow'=>'newBonusSwitch'],
             ['name'=>'往期奖金', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'other', 'routePath'=>'bonus/other', 'show'=>1,'allow'=>'pastBonusSwitch'],
             //['name'=>'实时业绩', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'real-time-perf', 'routePath'=>'bonus/real-time-perf', 'show'=>1,],
            // ['name'=>'房产积分', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'fc-point', 'routePath'=>'bonus/fc-point', 'show'=>1,],

+ 3 - 1
frontendApi/config/urlManagerRules.php

@@ -72,7 +72,9 @@ return [
             'GET pay-success' => 'pay-success',
             'GET order-list' => 'order-list',
             'GET dec-order-list' => 'dec-order-list',
-            'GET order-list' => 'order-list',
+            'GET goods-active' => 'goods-active',
+            'GET order-export/<orderSn>' => 'order-export',
+            'GET dec-order-export/<orderSn>' => 'dec-order-export',
         ],
     ],
     [

+ 144 - 91
frontendApi/modules/v1/controllers/BonusController.php

@@ -23,6 +23,7 @@ use common\models\FlowBonus;
 use common\models\FlowCF;
 use common\models\FlowLX;
 use common\models\FlowReconsumePoints;
+use common\models\FlowZonePoints;
 use common\models\FlowWallet;
 use common\models\PerfMonth;
 use common\models\Period;
@@ -44,12 +45,15 @@ class BonusController extends BaseController {
      */
     public function actionIndex() {
         $userId = \Yii::$app->user->id;
-        $data = UserBonus::findUseSlaves()->select('BONUS,RECONSUME_POINTS,EXCHANGE_POINTS')->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
+        $data = UserBonus::findUseSlaves()->select('BONUS,RECONSUME_POINTS,EXCHANGE_POINTS,TRAVEL_POINTS,CAR_POINTS,HOUSE_POINTS')->where('USER_ID=:USER_ID', [':USER_ID' => $userId])->asArray()->one();
         if (!$data) {
             $data = [
                 'BONUS' => 0,
-                'RECONSUME_POINTS' => 0,
+//                'RECONSUME_POINTS' => 0,
                 'EXCHANGE_POINTS' => 0,
+                'TRAVEL_POINTS' => 0,
+                'CAR_POINTS' => 0,
+                'HOUSE_POINTS'  => 0,
             ];
         }
         $data['CASH'] = 0;
@@ -68,8 +72,11 @@ class BonusController extends BaseController {
 //        }
         $wallet[] = ['walletType' => 'bonus', 'walletName' => '会员奖金', 'amount' => Tool::formatPrice($data['BONUS'])];
         $wallet[] = ['walletType' => 'cash', 'walletName' => '会员余额', 'amount' => Tool::formatPrice($data['CASH'])];
-        $wallet[] = ['walletType' => 'point', 'walletName' => '会员积分', 'amount' => Tool::formatPrice($data['RECONSUME_POINTS'])];
-        $wallet[] = ['walletType' => 'exchange', 'walletName' => '兑换积分', 'amount' => Tool::formatPrice($data['EXCHANGE_POINTS'])];
+//        $wallet[] = ['walletType' => 'point', 'walletName' => '会员积分', 'amount' => Tool::formatPrice($data['RECONSUME_POINTS'])];
+        $wallet[] = ['walletType' => 'exchange', 'walletName' => '兑换点数', 'amount' => Tool::formatPrice($data['EXCHANGE_POINTS'])];
+        $wallet[] = ['walletType' => 'travel_points', 'walletName' => '旅游积分', 'amount' => Tool::formatPrice($data['TRAVEL_POINTS'])];
+        $wallet[] = ['walletType' => 'car_points', 'walletName' => '名车积分', 'amount' => Tool::formatPrice($data['CAR_POINTS'])];
+        $wallet[] = ['walletType' => 'house_points', 'walletName' => '豪宅积分', 'amount' => Tool::formatPrice($data['HOUSE_POINTS'])];
 //        if ($showCFLX) {
 //            $wallet[] = ['walletType' => 'cf', 'walletName' => '福利积分一', 'amount' => Tool::formatPrice($data['CF'])];
 //            $wallet[] = ['walletType' => 'lx', 'walletName' => '福利积分二', 'amount' => Tool::formatPrice($data['LX'])];
@@ -101,7 +108,7 @@ class BonusController extends BaseController {
      */
     public function actionWalletFlow(){
         $walletType = \Yii::$app->request->get('walletType');
-        if(!in_array($walletType,['bonus','point','cash','exchange'])) return static::notice('错误的账户类型',400);
+        if(!in_array($walletType,['bonus', 'cash', 'exchange', 'travel_points', 'car_points', 'house_points'])) return static::notice('错误的账户类型',400);
         $dealType = \Yii::$app->request->get('dealType');
         $createAt = \Yii::$app->request->get('createAt');
         $remark = \Yii::$app->request->get('remark');
@@ -140,13 +147,13 @@ class BonusController extends BaseController {
                 'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
                 'orderBy' => 'CREATED_AT DESC,SORT DESC',
             ]);
-        }elseif ($walletType == 'point'){
-            $dealLists = FlowReconsumePoints::find()->groupBy('DEAL_TYPE_ID')->select('DEAL_TYPE_ID')->where('USER_ID=:USER_ID',[':USER_ID'=>\Yii::$app->user->id])->asArray()->all();
-            $data = FlowReconsumePoints::lists($condition, $params, [
-                'useSlaves' => true,
-                'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
-                'orderBy' => 'CREATED_AT DESC',
-            ]);
+//        }elseif ($walletType == 'point'){
+//            $dealLists = FlowReconsumePoints::find()->groupBy('DEAL_TYPE_ID')->select('DEAL_TYPE_ID')->where('USER_ID=:USER_ID',[':USER_ID'=>\Yii::$app->user->id])->asArray()->all();
+//            $data = FlowReconsumePoints::lists($condition, $params, [
+//                'useSlaves' => true,
+//                'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
+//                'orderBy' => 'CREATED_AT DESC',
+//            ]);
         }elseif ($walletType == 'cash'){
             $data = FlowWallet::lists($condition, $params, [
                 'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,PERIOD_NUM,CALC_MONTH,CREATED_AT',
@@ -159,7 +166,37 @@ class BonusController extends BaseController {
                 'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
                 'orderBy' => 'CREATED_AT DESC',
             ]);
+        } elseif (in_array($walletType, ['travel_points', 'car_points', 'house_points'])) {
+            $dealLists = FlowZonePoints::find()->groupBy('DEAL_TYPE_ID')->select('DEAL_TYPE_ID')->where('USER_ID=:USER_ID AND WALLET_TYPE=:WALLET_TYPE',[':USER_ID'=>\Yii::$app->user->id, ':WALLET_TYPE'=>$walletType])->asArray()->all();
+
+            $condition .= " AND WALLET_TYPE = :WALLET_TYPE";
+            $params[':WALLET_TYPE'] = $walletType;
+            $data = FlowZonePoints::lists($condition, $params, [
+                'useSlaves' => true,
+                'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
+                'orderBy' => 'CREATED_AT DESC',
+            ]);
+
+//            $dealTypeId = '';
+//            switch ($walletType) {
+//                case 'travel_points':
+//                    $dealTypeId = DealType::TRAVEL_SEND;
+//                    break;
+//                case 'car_points':
+//                    $dealTypeId = DealType::CAR_SEND;
+//                    break;
+//                case 'house_points':
+//                    $dealTypeId = DealType::HOUSE_SEND;
+//                    break;
+//            }
+//            $condition .= ' AND DEAL_TYPE_ID=:DEAL_TYPE_ID';
+//            $params[':DEAL_TYPE_ID'] = $dealTypeId;
+//            $data = FlowZonePoints::lists($condition, $params, [
+//                'select' => 'AMOUNT,TOTAL,IS_INCR,REMARK,REMARK_IS_SHOW,PERIOD_NUM,CALC_MONTH,CREATED_AT,DEAL_TYPE_ID,DEAL_TYPE_IS_PRESET',
+//                'orderBy' => 'CREATED_AT DESC',
+//            ]);
         }
+
         if($data) {
             if($walletType != 'cash') {
                 foreach ($data['list'] as $key => $value) {
@@ -233,37 +270,45 @@ class BonusController extends BaseController {
         $sysConfig = Cache::getSystemConfig();
 
         if($detailSwitch) {
-            $data[] = ['name' => '期数', 'value' => $periodNum];
-            $data[] = ['name' => '级别', 'value' => Cache::getDecLevelConfig()[$calcBonus['LAST_DEC_LV']]['LEVEL_NAME']];
-            $data[] = ['name' => '荣誉', 'value' => Cache::getEmpLevelConfig()[$calcBonus['LAST_EMP_LV']]['LEVEL_NAME']];
+            $data['PERIOD_NUM'] = ['name' => '期数', 'value' => $periodNum];
+            $data['LAST_DEC_LV'] = ['name' => '级别', 'value' => Cache::getDecLevelConfig()[$calcBonus['LAST_DEC_LV']]['LEVEL_NAME']];
+            $data['LAST_EMP_LV'] = ['name' => '荣誉', 'value' => Cache::getEmpLevelConfig()[$calcBonus['LAST_EMP_LV']]['LEVEL_NAME']];
             if ($sysConfig['openTG']['VALUE']) {
                 // 销售奖金 就是 原来的推广奖
-                $data[] = ['name' => '销售奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_TG'])];
+                $data['ORI_BONUS_TG'] = ['name' => '销售奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_TG'])];
             }
             if ($sysConfig['openQY']['VALUE']) {
                 // 业绩奖金  就是原来的团队奖 并将业绩奖金改成绩效奖金
                 // $data[] = ['name' => '团队奖', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_QY'])];
-                $data[] = ['name' => '绩奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_QY'])];
+                $data['ORI_BONUS_QY'] = ['name' => '绩奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_QY'])];
             }
             // 管理奖金 就是新的蓝星奖
-            $data[] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BS'])];
-            if ($sysConfig['openGX']['VALUE']) {
-                $data[] = ['name' => '共享奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_GX'])];
-            }
-            if ($sysConfig['openFW']['VALUE']) {
-                $data[] = ['name' => '服务奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BD'])];
-            }
-            $data[] = ['name' => '总奖金', 'value' => Tool::formatPrice($calcBonus['BONUS_TOTAL'])];
-            $data[] = ['name' => '管理费', 'value' => Tool::formatPrice($calcBonus['MANAGE_TAX'])];
-            $data[] = ['name' => '实发奖金', 'value' => Tool::formatPrice($calcBonus['BONUS_REAL'])];
-            $data[] = ['name' => '复消积分', 'value' => Tool::formatPrice($calcBonus['RECONSUME_POINTS'])];
-            $data[] = ['name' => '兑换积分', 'value' => Tool::formatPrice($calcBonus['EXCHANGE_POINTS'])];
-            $data[] = ['name' => '一市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_1L'])];
-            $data[] = ['name' => '二市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_2L'])];
-            $data[] = ['name' => '三市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_3L'])];
-            $data[] = ['name' => '一市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_1L'])];
-            $data[] = ['name' => '二市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_2L'])];
-            $data[] = ['name' => '三市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_3L'])];
+//            $data[] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BS'])];
+//            if ($sysConfig['openGX']['VALUE']) {
+//                $data[] = ['name' => '共享奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_GX'])];
+//            }
+//            if ($sysConfig['openFW']['VALUE']) {
+//                $data[] = ['name' => '服务奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BD'])];
+//            }
+            // 管理奖金 就是新的蓝星奖
+            $data['ORI_BONUS_BS_MNT'] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BS_MNT'])];
+            $data['ORI_BONUS_BS_ABBR'] = ['name' => '绩效奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_BS_ABBR'])];
+
+            $data['ORI_BONUS_QUARTER'] = ['name' => '季度奖金', 'value' => Tool::formatPrice($calcBonus['ORI_BONUS_QUARTER'])];
+            $data['BONUS_TRAVEL'] = ['name' => '旅游奖', 'value' => Tool::formatPrice($calcBonus['BONUS_TRAVEL'])];
+            $data['BONUS_CAR'] = ['name' => '名车奖', 'value' => Tool::formatPrice($calcBonus['BONUS_CAR'])];
+            $data['BONUS_HOUSE'] = ['name' => '豪宅奖', 'value' => Tool::formatPrice($calcBonus['BONUS_HOUSE'])];
+            $data['BONUS_TOTAL'] = ['name' => '合计', 'value' => Tool::formatPrice($calcBonus['BONUS_TOTAL'])];
+//            $data[] = ['name' => '管理费', 'value' => Tool::formatPrice($calcBonus['MANAGE_TAX'])];
+            $data['BONUS_REAL'] = ['name' => '实发奖金', 'value' => Tool::formatPrice($calcBonus['BONUS_REAL'])];
+//            $data[] = ['name' => '复消积分', 'value' => Tool::formatPrice($calcBonus['RECONSUME_POINTS'])];
+//            $data[] = ['name' => '兑换积分', 'value' => Tool::formatPrice($calcBonus['EXCHANGE_POINTS'])];
+            $data['PV_1L'] = ['name' => '一市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_1L'])];
+            $data['PV_2L'] = ['name' => '二市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_2L'])];
+            $data['PV_3L'] = ['name' => '三市场新增业绩', 'value' => Tool::formatFrontPerf($calcBonus['PV_3L'])];
+            $data['SURPLUS_1L'] = ['name' => '一市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_1L'])];
+            $data['SURPLUS_2L'] = ['name' => '二市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_2L'])];
+            $data['SURPLUS_3L'] = ['name' => '三市场结余业绩', 'value' => Tool::formatFrontPerf($calcBonus['SURPLUS_3L'])];
 
 
 
@@ -350,23 +395,31 @@ class BonusController extends BaseController {
                 }
                 // 业绩奖金,就是原来的团队奖  并将业绩奖金改成绩效奖金
                 if ($sysConfig['openQY']['VALUE']) {
-                    $calcBonus[$key]['BONUS_QY'] = ['name' => '绩奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_QY'])];
+                    $calcBonus[$key]['ORI_BONUS_QY'] = ['name' => '绩奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_QY'])];
                 }
                 // 管理奖金 就是新的蓝星奖金
-                $calcBonus[$key]['BONUS_BS'] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BS'])];
+//                $calcBonus[$key]['BONUS_BS'] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BS'])];
                 //共享奖
-                if ($sysConfig['openGX']['VALUE']) {
-                    $calcBonus[$key]['BONUS_GX'] = ['name' => '共享奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_GX'])];
-                }
+//                if ($sysConfig['openGX']['VALUE']) {
+//                    $calcBonus[$key]['BONUS_GX'] = ['name' => '共享奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_GX'])];
+//                }
                 //服务奖
-                if ($sysConfig['openFW']['VALUE']) {
-                    $calcBonus[$key]['BONUS_BD'] = ['name' => '服务奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BD'])];
-                }
+//                if ($sysConfig['openFW']['VALUE']) {
+//                    $calcBonus[$key]['BONUS_BD'] = ['name' => '服务奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BD'])];
+//                }
+                // 管理奖金 就是新的蓝星奖
+                $calcBonus[$key]['ORI_BONUS_BS_MNT'] = ['name' => '管理奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BS_MNT'])];
+                $calcBonus[$key]['ORI_BONUS_BS_ABBR'] = ['name' => '绩效奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_BS_ABBR'])];
+
+                $calcBonus[$key]['ORI_BONUS_QUARTER'] = ['name' => '季度奖金', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_QUARTER'])];
+                $calcBonus[$key]['BONUS_TRAVEL'] = ['name' => '旅游奖', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_TRAVEL'])];
+                $calcBonus[$key]['BONUS_CAR'] = ['name' => '名车奖', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_CAR'])];
+                $calcBonus[$key]['BONUS_HOUSE'] = ['name' => '豪宅奖', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_HOUSE'])];
                 // 总奖金
-                $calcBonus[$key]['BONUS_TOTAL'] = ['name' => '总奖金', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_TOTAL'])];
-                $calcBonus[$key]['RECONSUME_POINTS'] = ['name' => '复销积分', 'value' => Tool::formatPrice($calcBonus[$key]['RECONSUME_POINTS'])];
-                $calcBonus[$key]['EXCHANGE_POINTS'] = ['name' => '兑换积分', 'value' => Tool::formatPrice($calcBonus[$key]['EXCHANGE_POINTS'])];
-                $calcBonus[$key]['MANAGE_TAX'] = ['name' => '管理费', 'value' => Tool::formatPrice($calcBonus[$key]['MANAGE_TAX'])];
+                $calcBonus[$key]['BONUS_TOTAL'] = ['name' => '合计', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_TOTAL'])];
+//                $calcBonus[$key]['RECONSUME_POINTS'] = ['name' => '复销积分', 'value' => Tool::formatPrice($calcBonus[$key]['RECONSUME_POINTS'])];
+//                $calcBonus[$key]['EXCHANGE_POINTS'] = ['name' => '兑换积分', 'value' => Tool::formatPrice($calcBonus[$key]['EXCHANGE_POINTS'])];
+//                $calcBonus[$key]['MANAGE_TAX'] = ['name' => '管理费', 'value' => Tool::formatPrice($calcBonus[$key]['MANAGE_TAX'])];
                 $calcBonus[$key]['BONUS_REAL'] = ['name' => '实发奖金', 'value' => Tool::formatPrice($calcBonus[$key]['BONUS_REAL'])];
                 // if ($sysConfig['openYC']['VALUE']) {
                 //     $calcBonus[$key]['BONUS_YC'] = ['name' => '荣衔奖', 'value' => Tool::formatPrice($calcBonus[$key]['ORI_BONUS_YC'])];
@@ -393,50 +446,50 @@ class BonusController extends BaseController {
             }
         }
 
-        if($flowBonusSwitch) {
-            $tableKey[] = 'PERIOD_NUM';
-            if ($sysConfig['openTG']['VALUE']) {
-                $tableKey[] = 'BONUS_TG';
-            }
-            if ($sysConfig['openQY']['VALUE']) {
-                $tableKey[] = 'BONUS_QY';
-            }
-            $tableKey[] = 'BONUS_BS';
-            if ($sysConfig['openGX']['VALUE']) {
-                $tableKey[] = 'BONUS_GX';
-            }
-            // if ($sysConfig['openYC']['VALUE']) {
-            //     $tableKey[] = 'BONUS_YC';
-            // }
-            // if ($sysConfig['openVIP']['VALUE']) {
-            //     $tableKey[] = 'BONUS_VIP';
-            // }
-            if ($sysConfig['openFW']['VALUE']) {
-                $tableKey[] = 'BONUS_BD';
-            }
-            
-            // if ($sysConfig['openXF']['VALUE']) {
-            //     $tableKey[] = 'BONUS_XF';
-            // }
-            // if ($sysConfig['openYJ']['VALUE']) {
-            //     $tableKey[] = 'BONUS_YJ';
-            // }
-            
-            // if ($sysConfig['openGL']['VALUE']) {
-            //     $tableKey[] = 'BONUS_GL';
-            // }
-            // if ($sysConfig['openJXS']['VALUE']) {
-            //     $tableKey[] = 'BONUS_STANDARD';
-            // }
-           
-            $tableKey[] = 'BONUS_TOTAL';
-            $tableKey[] = 'RECONSUME_POINTS';
-            $tableKey[] = 'EXCHANGE_POINTS';
-            $tableKey[] = 'MANAGE_TAX';
-            $tableKey[] = 'BONUS_REAL';
-        }else{
-            $tableKey[] = 'BONUS_TOTAL';
-        }
+//        if($flowBonusSwitch) {
+//            $tableKey[] = 'PERIOD_NUM';
+//            if ($sysConfig['openTG']['VALUE']) {
+//                $tableKey[] = 'BONUS_TG';
+//            }
+//            if ($sysConfig['openQY']['VALUE']) {
+//                $tableKey[] = 'BONUS_QY';
+//            }
+//            $tableKey[] = 'BONUS_BS';
+//            if ($sysConfig['openGX']['VALUE']) {
+//                $tableKey[] = 'BONUS_GX';
+//            }
+//            // if ($sysConfig['openYC']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_YC';
+//            // }
+//            // if ($sysConfig['openVIP']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_VIP';
+//            // }
+//            if ($sysConfig['openFW']['VALUE']) {
+//                $tableKey[] = 'BONUS_BD';
+//            }
+//
+//            // if ($sysConfig['openXF']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_XF';
+//            // }
+//            // if ($sysConfig['openYJ']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_YJ';
+//            // }
+//
+//            // if ($sysConfig['openGL']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_GL';
+//            // }
+//            // if ($sysConfig['openJXS']['VALUE']) {
+//            //     $tableKey[] = 'BONUS_STANDARD';
+//            // }
+//
+//            $tableKey[] = 'BONUS_TOTAL';
+//            $tableKey[] = 'RECONSUME_POINTS';
+//            $tableKey[] = 'EXCHANGE_POINTS';
+//            $tableKey[] = 'MANAGE_TAX';
+//            $tableKey[] = 'BONUS_REAL';
+//        }else{
+//            $tableKey[] = 'BONUS_TOTAL';
+//        }
 
         return static::notice(['tableData' => $calcBonus, 'tableKey' => $tableKey]);
     }

+ 499 - 8
frontendApi/modules/v1/controllers/ShopController.php

@@ -8,20 +8,26 @@
 
 namespace frontendApi\modules\v1\controllers;
 
+use Codeception\PHPUnit\ResultPrinter\HTML;
 use common\helpers\Date;
 use common\helpers\Form;
 use common\helpers\user\Info;
+use common\models\DealType;
 use common\models\DecOrder;
 use common\models\forms\DeclarationForm;
 use common\models\forms\OrderForm;
 use common\models\Order;
+use common\models\OrderDec;
 use common\models\OrderGoods;
+use common\models\OrderGoodsDec;
 use common\models\ReceiveAddress;
 use common\models\Region;
 use common\models\ShopGoods;
 use common\models\User;
 use common\models\UserBonus;
 use common\models\UserWallet;
+use Yii;
+
 
 class ShopController extends BaseController {
     public $modelClass = DecOrder::class;
@@ -32,14 +38,18 @@ class ShopController extends BaseController {
      * @throws \yii\web\HttpException
      */
     public function actionIndex() {
+        // 商品分类
+        $categoryType = \Yii::$app->request->get('categoryType', 1);
+
         $condition = ' AND STATUS=1 AND (FIND_IN_SET(2,GIFT_TYPE)>0';
         $isStudio = User::getEnCodeInfo(\Yii::$app->user->id)['IS_STUDIO'];
         if($isStudio==1){
             $condition.= " OR FIND_IN_SET(4,GIFT_TYPE)>0";
         }
-        $condition.=")";
+        $condition .= ") AND CATEGORY_TYPE = :CATEGORY_TYPE";
+        $params[':CATEGORY_TYPE'] = intval($categoryType);
 
-        $data = ShopGoods::lists($condition, [], [
+        $data = ShopGoods::lists($condition, $params, [
             'orderBy' => 'SORT ASC,CREATED_AT DESC',
             'from' => ShopGoods::tableName(),
         ]);
@@ -86,16 +96,29 @@ class ShopController extends BaseController {
         $userBalance = [
             'points' => 0,
             'cash' => 0,
-            'exchange' => 0
+            'exchange' => 0,
+            'travel_points' => 0,
+            'car_points' => 0,
+            'house_points' => 0,
         ];
         if ($userBonusResult = UserBonus::findOneAsArray(['USER_ID' => $userId])) {
             $userBalance['points'] = $userBonusResult['RECONSUME_POINTS'];
             $userBalance['exchange'] = $userBonusResult['EXCHANGE_POINTS'];
+            $userBalance['travel_points'] = $userBonusResult['TRAVEL_POINTS'];
+            $userBalance['car_points'] = $userBonusResult['CAR_POINTS'];
+            $userBalance['house_points'] = $userBonusResult['HOUSE_POINTS'];
         }
         if ($userCashResult = UserWallet::findOneAsArray(['USER_ID' => $userId])) {
             $userBalance['cash'] = $userCashResult['CASH'];
         }
-        return static::notice(['payList'=>$payList,'allAddress'=>$allAddress,'userBalance'=>$userBalance]);
+
+        return static::notice(
+            [
+                'payList'=>$payList,
+                'allAddress'=>$allAddress,
+                'userBalance'=>$userBalance,
+                'sellType' => ShopGoods::CATEGORY_TYPE,
+            ]);
     }
 
     /**
@@ -161,19 +184,30 @@ class ShopController extends BaseController {
         $condition = " AND ORDER_TYPE='FX' AND (USER_ID=:USER_ID OR CREATE_USER='$uname')";
         $params[':USER_ID'] = \Yii::$app->user->id;
         $data = Order::lists($condition, $params, [
-            'select' => 'O.*,U.REAL_NAME,OG.*',
+            'select' => 'O.*,U.REAL_NAME,OG.*,SG.CATEGORY_TYPE',
             'orderBy' => 'O.CREATED_AT DESC',
             'from' => Order::tableName() . ' AS O',
             'join' => [
                 ['LEFT JOIN', User::tableName() . ' AS U', 'U.ID=O.USER_ID'],
                 ['LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=O.SN'],
+                ['LEFT JOIN', ShopGoods::tableName() . ' AS SG', 'SG.ID=OG.GOODS_ID'],
             ],
         ]);
         foreach ($data['list'] as $key => $value) {
-            //$data['list'][$key]['PROVINCE_NAME'] = $value['PROVINCE'] ? Region::getCnName($value['PROVINCE']) : '';
-           //$data['list'][$key]['CITY_NAME'] = $value['CITY'] ? Region::getCnName($value['CITY']) : '';
-            //$data['list'][$key]['COUNTY_NAME'] = $value['COUNTY'] ? Region::getCnName($value['COUNTY']) : '';
             $data['list'][$key]['PAY_AT'] = Date::convert($value['PAY_AT'],'Y-m-d H:i:s');
+            $data['list'][$key]['CATEGORY_TYPE'] = intval($value['CATEGORY_TYPE']);
+            $data['list'][$key]['CATEGORY'] = array_column(ShopGoods::CATEGORY_TYPE, NULL, 'id')[$value['CATEGORY_TYPE']]['name'] ?? '普通商品';
+            $data['list'][$key]['FULL_ADDRESS'] = '';
+            if($value['PROVINCE']){
+                $data['list'][$key]['FULL_ADDRESS'] .= Region::getCnName($value['PROVINCE']);
+            }
+            if($value['CITY']){
+                $data['list'][$key]['FULL_ADDRESS'] .= Region::getCnName($value['CITY']);
+            }
+            if($value['COUNTY']){
+                $data['list'][$key]['FULL_ADDRESS'] .= Region::getCnName($value['COUNTY']);
+            }
+            $data['list'][$key]['FULL_ADDRESS'] .= $value['ADDRESS'];
         }
         return static::notice($data);
     }
@@ -236,4 +270,461 @@ class ShopController extends BaseController {
         }
     }
 
+    /**
+     * 商品列表tabs分类
+     * @return mixed
+     * @throws \yii\web\HttpException
+     */
+    public function actionGoodsActive()
+    {
+        $data = [
+//            [
+//                'name' => 'bonus',
+//                'label' => '奖金商品',
+//            ],
+            [
+                'name' => '1',
+                'label' => '普通商品列表',
+            ],
+            [
+                'name' => '4',
+                'label' => '旅游积分商品',
+            ],
+            [
+                'name' => '5',
+                'label' => '名车积分商品',
+            ],
+            [
+                'name' => '6',
+                'label' => '豪宅积分商品',
+            ],
+        ];
+        return static::notice($data);
+    }
+
+    /**
+     * 导出订单.
+     * @return mixed
+     * @throws \yii\web\HttpException
+     * @throws \Mpdf\MpdfException
+     */
+    public function actionOrderExport()
+    {
+        $uname = Info::getUserNameByUserId(\Yii::$app->user->id);
+        $orderSn = \Yii::$app->request->get('orderSn');
+
+        $condition = " AND ORDER_TYPE='FX' AND (USER_ID=:USER_ID OR CREATE_USER='$uname') AND SN=:SN";
+        $params = [
+            ':USER_ID' => \Yii::$app->user->id,
+            ':SN' => $orderSn,
+        ];
+
+        $data = Order::lists($condition, $params, [
+            'select' => 'O.*,U.REAL_NAME,OG.*,OG.CATEGORY_TYPE',
+            'orderBy' => 'O.CREATED_AT DESC',
+            'from' => Order::tableName() . ' AS O',
+            'join' => [
+                ['LEFT JOIN', User::tableName() . ' AS U', 'U.ID=O.USER_ID'],
+                ['LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=O.SN'],
+            ],
+        ]);
+
+        $userId = '';
+        $userName = '';
+        $address = '';
+        $mobile = '';
+        $orderAt = '';
+        $orderDetails = '';
+        $orderAmount = 0;  // 合计总额
+        $orderNums = 0; // 合计总数
+        foreach ($data['list'] as $key => $value) {
+            $provinceName = $value['PROVINCE'] ? Region::getCnName($value['PROVINCE']) : '';
+            $cityName = $value['CITY'] ? Region::getCnName($value['CITY']) : '';
+            $countyName = $value['COUNTY'] ? Region::getCnName($value['COUNTY']) : '';
+
+            $userId = $value['USER_NAME'];
+            $userName = $value['REAL_NAME'];
+            $address = $provinceName . $cityName . $countyName . $value['ADDRESS'];
+            $mobile = $value['MOBILE'];
+            $orderAt = Date::convert($value['PAY_AT'],'Y-m-d H:i:s');
+
+            // 总价
+            $totalAmount = $value['BUY_NUMS'] * $value['ORDER_AMOUNT'];
+            $orderAmount += $totalAmount;
+            $orderNums += $value['BUY_NUMS'];
+            // 订单详情
+            $orderDetails .= <<<EOT
+                <tr>
+                    <td>{$value['SKU_CODE']}</td>
+                    <td>{$value['GOODS_TITLE']}</td>
+                    <td>{$value['BUY_NUMS']}</td>
+                    <td>{$value['ORDER_AMOUNT']}</td>
+                    <td>{$totalAmount}</td> 
+                </tr>
+EOT;
+        }
+
+        // 订单基本信息
+        $orderBase = <<<ORDER
+            <table border="1" style="table-layout: fixed; padding: 10px 20px;" width="100%">
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员编号</td>
+                    <td width="70%">{$userId}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员名字</td>
+                    <td width="70%">{$userName}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员地址</td>
+                    <td width="70%">{$address}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员电话</td>
+                    <td width="70%">{$mobile}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单编号</td>
+                    <td width="70%">{$orderSn}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单日期</td>
+                    <td width="70%">{$orderAt}</td>
+                </tr>
+                <tr>
+                    <td class="bg" style="font-weight: bold; font-size: 14px; text-align: center;">订单明细</td>
+                    <td class="bg"></td>
+                </tr>
+            </table>
+ORDER;
+
+        $l['a_meta_charset'] = 'UTF-8';
+        $l['a_meta_dir'] = 'ltr';
+        $l['a_meta_language'] = 'zh';
+        $l['w_page'] = '页面';
+
+        $context = <<<ORDER
+            <!doctype html>
+            <html lang="en">
+            <head>
+                <meta charset="UTF-8" />
+                <title>订单详情</title>
+                <style>
+                    table {
+                        border-collapse: collapse;
+                    }
+                    table td, table th {
+                        border: 1px solid #ccc;
+                        padding: 10px 30px;
+                        border-collapse: collapse;
+                    }
+                    td {
+                        padding: 120px;
+                    }
+                    .bg {
+                        background-color: #ccc;
+                    }
+                </style>
+            </head>
+            <body>
+                <div class="content">
+                    <p style="text-align: center; font-weight: bold; font-size: 22px;"><b>订单详情</b><br></p>
+                    <div>
+                        <div style="display: block; width: 100%;">
+                            {$orderBase}
+                            
+                            <table border="1" width="100%" style="padding: 10px 20px; text-align: center;">
+                                <tr>
+                                    <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">商品编号</th>
+                                    <th width="30%" style="font-size: 14px; font-weight: bold; text-align: center;">商品名称</th>
+                                    <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">数量</th>
+                                    <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">单价</th>
+                                    <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">总价</th>
+                                </tr>
+                                {$orderDetails}
+                                <tr>
+                                    <td colspan="2">合计</td>
+                                    <td>{$orderNums}</td>
+                                    <td></td>
+                                    <td>{$orderAmount}</td>
+                                </tr>
+                            </table>
+                        </div>
+                        
+                        <div style="width: 100%; margin-top: 50px; height: 30px;">
+                            <table width="100%" style="border: none; padding: 10px 20px; text-align: center;">
+                                <tr style="border: none;">
+                                    <td width="70%" style="border: none;"></td>
+                                    <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">签名:</td>
+                                </tr>
+                                <tr style="border: none;">
+                                    <td width="70%" style="border: none;"></td>
+                                    <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">日期:</td>
+                                </tr>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            </body>
+            </html>
+ORDER;
+        require_once (\Yii::$app->vendorPath . '/tecnickcom/tcpdf/tcpdf.php');
+
+        $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
+        // 设置打印模式
+        $pdf->SetCreator(PDF_CREATOR);
+        $pdf->SetAuthor('DaZe');
+        $pdf->SetTitle($orderSn);
+        $pdf->SetSubject('TCPDF Tutorial');
+        $pdf->SetKeywords('TCPDF, PDF, example, test, guide');
+        // 是否显示页眉
+        $pdf->setPrintHeader(false);
+        // 设置页眉字体
+        $pdf->setHeaderFont(Array('dejavusans', '', '12'));
+        // 页眉距离顶部的距离
+        $pdf->SetHeaderMargin('5');
+        // 是否显示页脚
+        $pdf->setPrintFooter(false);
+        // 设置默认等宽字体
+        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
+        // 设置行高
+        $pdf->setCellHeightRatio(1);
+        // 设置左、上、右的间距
+        $pdf->SetMargins('10', '10', '10');
+        // 设置是否自动分页  距离底部多少距离时分页
+        $pdf->SetAutoPageBreak(TRUE, '15');
+        // 设置图像比例因子
+        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
+        if (@file_exists(\Yii::$app->vendorPath . 'tecnickcom/tcpdf/examples/lang/eng.php')) {
+            require_once(\Yii::$app->vendorPath . '/tecnickcom/tcpdf/examples/lang/eng.php');
+            $pdf->setLanguageArray($l);
+        }
+        $pdf->setFontSubsetting(true);
+        $pdf->AddPage();
+        // 设置字体
+        $pdf->SetFont('stsongstdlight', '', 10, '', true);
+        $pdf->writeHTML($context);
+
+        ob_clean();
+
+        $file_name = $orderSn . '.pdf';
+        $path = '/pdfs/' . $file_name;
+        $pdf->Output(Yii::$app->basePath . '/web' . $path, 'F');
+
+        return static::notice(['fileUrl' => $path, 'targetName' => $file_name]);
+    }
+
+    /**
+     * 导出订单.
+     * @return mixed
+     * @throws \yii\web\HttpException
+     * @throws \Mpdf\MpdfException
+     */
+    public function actionDecOrderExport()
+    {
+        $orderSn = \Yii::$app->request->get('orderSn');
+
+        $condition = ' AND DO.USER_ID=:USER_ID AND IS_DEL=0 AND DO.ORDER_SN=:ORDER_SN';
+        $params = [
+            ':USER_ID'  => \Yii::$app->user->id,
+            ':ORDER_SN' => $orderSn,
+        ];
+        $data = DecOrder::lists($condition, $params, [
+            'select' => 'DO.*,U.USER_NAME USER_NAME,U.REAL_NAME REAL_NAME,RU.USER_NAME REC_USER_NAME,RU.REAL_NAME REC_REAL_NAME,CU.USER_NAME CON_USER_NAME,CU.REAL_NAME CON_REAL_NAME,OG.*,OD.PROVINCE,OD.CITY,OD.COUNTY,OD.ADDRESS,OD.MOBILE,OD.PAY_AT,OD.ORDER_AMOUNT',
+            'orderBy' => 'DO.CREATED_AT DESC',
+            'from' => DecOrder::tableName() . ' AS DO',
+            'join' => [
+                ['LEFT JOIN', User::tableName() . ' AS U', 'DO.TO_USER_ID=U.ID'],
+                ['LEFT JOIN', User::tableName() . ' AS RU', 'DO.REC_USER_ID=RU.ID'],
+                ['LEFT JOIN', User::tableName() . ' AS CU', 'DO.CON_USER_ID=CU.ID'],
+                ['LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=DO.ORDER_SN'],
+                ['LEFT JOIN', Order::tableName() . ' AS OD', 'OD.SN=DO.ORDER_SN'],
+            ],
+        ]);
+
+        $userId = '';
+        $userName = '';
+        $address = '';
+        $mobile = '';
+        $orderAt = '';
+        $orderDetails = '';
+        $orderAmount = 0;  // 合计总额
+        $orderNums = 0; // 合计总数
+        foreach ($data['list'] as $key => $value) {
+            $provinceName = $value['PROVINCE'] ? Region::getCnName($value['PROVINCE']) : '';
+            $cityName = $value['CITY'] ? Region::getCnName($value['CITY']) : '';
+            $countyName = $value['COUNTY'] ? Region::getCnName($value['COUNTY']) : '';
+
+            $userId = $value['USER_NAME'];
+            $userName = $value['REAL_NAME'];
+            $address = $provinceName . $cityName . $countyName . $value['ADDRESS'];
+            $mobile = $value['MOBILE'];
+            $orderAt = Date::convert($value['PAY_AT'],'Y-m-d H:i:s');
+
+            // 总价
+            $totalAmount = $value['BUY_NUMS'] * $value['REAL_PRICE'];
+            $orderAmount += $totalAmount;
+            $orderNums += $value['BUY_NUMS'];
+
+            // 订单详情
+            $orderDetails .= <<<EOT
+                <tr>
+                    <td>{$value['SKU_CODE']}</td>
+                    <td>{$value['GOODS_TITLE']}</td>
+                    <td>{$value['BUY_NUMS']}</td>
+                    <td>{$value['REAL_PRICE']}</td>
+                    <td>{$totalAmount}</td> 
+                </tr>
+EOT;
+        }
+
+        // 订单基本信息
+        $orderBase = <<<ORDER
+            <table border="1" style="table-layout: fixed; padding: 10px 20px;" width="100%">
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员编号</td>
+                    <td width="70%">{$userId}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员名字</td>
+                    <td width="70%">{$userName}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员地址</td>
+                    <td width="70%">{$address}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">会员电话</td>
+                    <td width="70%">{$mobile}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单编号</td>
+                    <td width="70%">{$orderSn}</td>
+                </tr>
+                <tr>
+                    <td width="30%" style="font-weight: bold; text-align: center; font-size: 14px;">订单日期</td>
+                    <td width="70%">{$orderAt}</td>
+                </tr>
+                <tr>
+                    <td class="bg" style="font-weight: bold; font-size: 14px; text-align: center;">订单明细</td>
+                    <td class="bg"></td>
+                </tr>
+            </table>
+ORDER;
+
+        $l['a_meta_charset'] = 'UTF-8';
+        $l['a_meta_dir'] = 'ltr';
+        $l['a_meta_language'] = 'zh';
+        $l['w_page'] = '页面';
+
+        $context = <<<ORDER
+            <!doctype html>
+            <html lang="en">
+            <head>
+                <meta charset="UTF-8" />
+                <title>订单详情</title>
+                <style>
+                    table {
+                        border-collapse: collapse;
+                    }
+                    table td, table th {
+                        border: 1px solid #ccc;
+                        padding: 10px 30px;
+                        border-collapse: collapse;
+                    }
+                    td {
+                        padding: 120px;
+                    }
+                    .bg {
+                        background-color: #ccc;
+                    }
+                </style>
+            </head>
+            <body>
+                <div class="content">
+                    <p style="text-align: center; font-weight: bold; font-size: 22px;"><b>订单详情</b><br></p>
+                    <div>
+                        <div style="display: block; width: 100%;">
+                            {$orderBase}
+                            
+                            <table border="1" width="100%" style="padding: 10px 20px; text-align: center;">
+                                <tr>
+                                    <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">商品编号</th>
+                                    <th width="30%" style="font-size: 14px; font-weight: bold; text-align: center;">商品名称</th>
+                                    <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">数量</th>
+                                    <th width="15%" style="font-size: 14px; font-weight: bold; text-align: center;">单价</th>
+                                    <th width="20%" style="font-size: 14px; font-weight: bold; text-align: center;">总价</th>
+                                </tr>
+                                {$orderDetails}
+                                <tr>
+                                    <td colspan="2">合计</td>
+                                    <td>{$orderNums}</td>
+                                    <td></td>
+                                    <td>{$orderAmount}</td>
+                                </tr>
+                            </table>
+                        </div>
+                        
+                        <div style="width: 100%; margin-top: 50px; height: 30px;">
+                            <table width="100%" style="border: none; padding: 10px 20px; text-align: center;">
+                                <tr style="border: none;">
+                                    <td width="70%" style="border: none;"></td>
+                                    <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">签名:</td>
+                                </tr>
+                                <tr style="border: none;">
+                                    <td width="70%" style="border: none;"></td>
+                                    <td width="30%" style="font-weight: bold; text-align: left; font-size: 14px; border: none;">日期:</td>
+                                </tr>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            </body>
+            </html>
+ORDER;
+        require_once (\Yii::$app->vendorPath . '/tecnickcom/tcpdf/tcpdf.php');
+
+        $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
+        // 设置打印模式
+        $pdf->SetCreator(PDF_CREATOR);
+        $pdf->SetAuthor('DaZe');
+        $pdf->SetTitle($orderSn);
+        $pdf->SetSubject('TCPDF Tutorial');
+        $pdf->SetKeywords('TCPDF, PDF, example, test, guide');
+        // 是否显示页眉
+        $pdf->setPrintHeader(false);
+        // 设置页眉字体
+        $pdf->setHeaderFont(Array('dejavusans', '', '12'));
+        // 页眉距离顶部的距离
+        $pdf->SetHeaderMargin('5');
+        // 是否显示页脚
+        $pdf->setPrintFooter(false);
+        // 设置默认等宽字体
+        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
+        // 设置行高
+        $pdf->setCellHeightRatio(1);
+        // 设置左、上、右的间距
+        $pdf->SetMargins('10', '10', '10');
+        // 设置是否自动分页  距离底部多少距离时分页
+        $pdf->SetAutoPageBreak(TRUE, '15');
+        // 设置图像比例因子
+        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
+        if (@file_exists(\Yii::$app->vendorPath . 'tecnickcom/tcpdf/examples/lang/eng.php')) {
+            require_once(\Yii::$app->vendorPath . '/tecnickcom/tcpdf/examples/lang/eng.php');
+            $pdf->setLanguageArray($l);
+        }
+        $pdf->setFontSubsetting(true);
+        $pdf->AddPage();
+        // 设置字体
+        $pdf->SetFont('stsongstdlight', '', 10, '', true);
+        $pdf->writeHTML($context);
+
+        ob_clean();
+
+        $file_name = $orderSn . '.pdf';
+        $path = '/pdfs/' . $file_name;
+        $pdf->Output(Yii::$app->basePath . '/web' . $path, 'F');
+
+        return static::notice(['fileUrl' => $path, 'targetName' => $file_name]);
+    }
 }

+ 4 - 0
frontendApi/modules/v1/controllers/UserController.php

@@ -212,6 +212,10 @@ class UserController extends BaseController {
             $formModel->scenario = 'userDec';
             $post = \Yii::$app->request->post();
 
+            $post['province'] = $post['province'] ? :1;
+            $post['city'] = $post['city'] ? :1;
+            $post['county'] = $post['county'] ? :1;
+
             // 针对于会员编号的判断
             $insertUserName = strtoupper($post['insertUserName']);
             $getRedisUserName = $redis->get('key_'.$insertUserName);

+ 46 - 17
frontendEle/src/views/bonus/other.vue

@@ -1,15 +1,29 @@
 <template>
   <div v-loading="loading">
     <div class="white-box">
-      <el-table class="table-box other-table-box" :data="tableData" style="width: 100%;">
-        <el-table-column v-for="(item,key) in tableKey" :key="key">
-          <template slot-scope="scope">
-            <el-tooltip effect="dark" :content="scope.row[item].name" placement="top">
-            <div class="bonus-item">{{scope.row[item].value}}</div>
-            </el-tooltip>
-          </template>
+      <el-table class="table-box" :data="tableData" style="width: 100%;">
+        <el-table-column label="期数" prop="PERIOD_NUM.value">
+        </el-table-column>
+        <el-table-column label="销售奖金" prop="BONUS_TG.value">
+        </el-table-column>
+        <el-table-column label="业绩奖金" prop="ORI_BONUS_QY.value">
+        </el-table-column>
+        <el-table-column label="管理奖金" prop="ORI_BONUS_BS_MNT.value">
+        </el-table-column>
+        <el-table-column label="绩效奖金" prop="ORI_BONUS_BS_ABBR.value">
+        </el-table-column>
+        <el-table-column label="季度分红" prop="ORI_BONUS_QUARTER.value">
+        </el-table-column>
+        <el-table-column label="旅游奖" prop="BONUS_TRAVEL.value">
+        </el-table-column>
+        <el-table-column label="名车奖" prop="BONUS_CAR.value">
+        </el-table-column>
+        <el-table-column label="豪宅奖" prop="BONUS_HOUSE.value">
+        </el-table-column>
+        <el-table-column label="合计" prop="BONUS_TOTAL.value">
+        </el-table-column>
+        <el-table-column label="实发" prop="BONUS_REAL.value">
         </el-table-column>
-
         <el-table-column >
           <template slot-scope="scope">
             <el-button type="primary" size="small" @click.native="showFlow(scope.row.PERIOD_NUM.value)">查看全部</el-button>
@@ -18,14 +32,28 @@
 
       </el-table>
     </div>
-    <el-dialog :title="`${periodNum}期奖金`" :visible.sync="dialogFlowVisible" width="80%">
-      <div class="bonus-list" v-loading="dialogLoading">
-        <div class="bonus-item" v-for="(item,key) in newData" :key="key">
-          <el-tooltip effect="dark" :content="item.name" placement="top-end">
-            <div>{{item.value}}</div>
-          </el-tooltip>
-        </div>
-      </div>
+    <el-dialog :title="`${periodNum}期奖金`" :visible.sync="dialogFlowVisible" width="70%">
+
+        <el-descriptions title="" class="bonus-list" v-if="newData" :column="2">
+          <el-descriptions-item class="bonus-item" label="期数">{{newData.PERIOD_NUM.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="会员等级">{{newData.LAST_DEC_LV.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="销售奖金">{{newData.ORI_BONUS_TG.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="业绩奖金">{{newData.ORI_BONUS_QY.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="管理奖金">{{newData.ORI_BONUS_BS_MNT.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="绩效奖金">{{newData.ORI_BONUS_BS_ABBR.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="季度分红">{{newData.ORI_BONUS_QUARTER.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="旅游奖">{{newData.BONUS_TRAVEL.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="名车奖">{{newData.BONUS_CAR.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="豪宅奖">{{newData.BONUS_HOUSE.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="合计">{{newData.BONUS_TOTAL.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="实发奖金">{{newData.BONUS_REAL.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="一市场新增">{{newData.PV_1L.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="一市场结余">{{newData.SURPLUS_1L.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="二市场新增">{{newData.PV_2L.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="二市场结余">{{newData.SURPLUS_2L.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="三市场新增">{{newData.PV_3L.value}}</el-descriptions-item>
+          <el-descriptions-item class="bonus-item" label="三市场结余">{{newData.SURPLUS_3L.value}}</el-descriptions-item>
+        </el-descriptions>
     </el-dialog>
   </div>
 </template>
@@ -95,7 +123,8 @@
   .other-table-box .el-table__body tr:hover>td{background-color: #fff!important;}
   .other-table-box .el-table__body tr td:not(:last-child):hover{background-color: #f5f5f5!important;}
   .bonus-list:after{content: '';clear: both;display: table;}
+  .bonus-list{width: 360px;}
   .bonus-list .bonus-item{float: left;width: 33.333%;background: #fff;height:36px;line-height:36px;border: 1px solid #ddd;margin: -1px 0 0 -1px;box-sizing: border-box;}
   .bonus-item{text-align: center;}
   .bonus-item:hover{background: #f5f5f5;cursor: pointer;}
-</style>
+</style>

+ 22 - 2
frontendEle/src/views/shop/dec-order-list.vue

@@ -11,12 +11,18 @@
                 <el-table-column label="订单编号" prop="ORDER_SN"></el-table-column>
                 <el-table-column label="会员编号" prop="USER_NAME"></el-table-column>
                 <el-table-column label="会员姓名" prop="REAL_NAME"></el-table-column>
+                <el-table-column label="收货地址" prop="ADDRESS"></el-table-column>
                 <el-table-column label="接点人编号" prop="CON_USER_NAME"></el-table-column>
                 <el-table-column label="创建时间">
                     <template slot-scope="scope">
                         {{tool.formatDate(scope.row.CREATED_AT)}}
                     </template>
                 </el-table-column>
+                <el-table-column label="操作">
+                    <template slot-scope="scope">
+                        <el-button type="primary" size="small" @click.native="handleOrderExportPDF(scope.row.ORDER_SN)">导出PDF</el-button>
+                    </template>
+                </el-table-column>
             </el-table>
             <div class="white-box-footer">
                 <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
@@ -65,7 +71,8 @@
           obj.columnIndex === 7 ||
           obj.columnIndex === 8 ||
           obj.columnIndex === 9 ||
-          obj.columnIndex === 10
+          obj.columnIndex === 10||
+          obj.columnIndex === 11
         ) {
           // ⼆维数组存储的数据取出
           var _row = this.spanArr[obj.rowIndex];
@@ -95,7 +102,7 @@
               orderList[index].USER_NAME === orderList[index - 1].USER_NAME &&
               orderList[index].REAL_NAME === orderList[index - 1].REAL_NAME &&
               orderList[index].CON_USER_NAME === orderList[index - 1].CON_USER_NAME &&
-              orderList[index].P_CALC_MONTH === orderList[index - 1].P_CALC_MONTH 
+              orderList[index].P_CALC_MONTH === orderList[index - 1].P_CALC_MONTH
             ) {
               // 查找到符合条件的数据时每次要把之前存储的数据+1
               this.spanArr[this.pos] += 1;
@@ -137,7 +144,20 @@
                     _this.getSpanArr(_this.tableData);
                 });
             },
+            // 导出PDF订单
+            handleOrderExportPDF (orderSn) {
+                network.getData(`shop/dec-order-export/${orderSn}`).then(response => {
+                    let { fileUrl, targetName } = response
 
+                    let downloadElement = document.createElement('a')
+                    downloadElement.target = '_blank'
+                    downloadElement.href = fileUrl
+                    // 下载后文件名
+                    downloadElement.download = targetName
+                    //点击下载
+                    downloadElement.click()
+                })
+            },
         }
     }
 </script>

+ 67 - 36
frontendEle/src/views/shop/index.vue

@@ -1,41 +1,50 @@
 <template>
     <div v-loading="loading">
         <div class="white-box">
-            <el-table v-if="numList.length > 0" class="withdraw-table" :data="tableData" stripe style="width: 100%;" ref="multipleTable"
-             @selection-change="handleSelectionChange">
-                <el-table-column
-                    type="selection"
-                    width="55">
-                </el-table-column>
-                <!-- <el-table-column label="创建时间"> 
-                     <template slot-scope="scope">
-                        {{tool.formatDate(scope.row.CREATED_AT)}}
-                    </template> 
-                </el-table-column> -->
-                <el-table-column label="商品名称" prop="GOODS_NAME">
-                   
-                </el-table-column>
+            <el-tabs v-model="goodsCategory" @tab-click="handleClick">
+                <el-tab-pane v-for="(item, key) in goodsActive" :key="key" :label="item.label" :name="item.name">
+                    <el-table v-if="numList.length > 0" class="withdraw-table" :data="tableData" stripe style="width: 100%;" ref="multipleTable" @selection-change="handleSelectionChange">
+                      <el-table-column
+                          type="selection"
+                          width="55">
+                      </el-table-column>
+                      <!-- <el-table-column label="创建时间">
+                           <template slot-scope="scope">
+                              {{tool.formatDate(scope.row.CREATED_AT)}}
+                          </template>
+                      </el-table-column> -->
+                      <el-table-column label="商品名称" prop="GOODS_NAME">
 
-                <el-table-column label="图片" >
-                     <template slot-scope="scope">
-                        <img :src="scope.row.COVER" alt="" style="width:100%" >
-                    </template>
-                </el-table-column>
+                      </el-table-column>
 
-                <el-table-column label="商品价格" prop="SELL_PRICE">
-                </el-table-column>
-                <el-table-column label="价格PV" prop="PRICE_PV">
-                </el-table-column>
-                <el-table-column label="库存" prop="STORE_NUMS">
-                </el-table-column>
+                      <el-table-column label="图片" >
+                        <template slot-scope="scope">
+                          <img :src="scope.row.COVER" alt="" style="width:100px" >
+                        </template>
+                      </el-table-column>
 
-                <el-table-column label="数量"  width="155">
-                    <template slot-scope="scope">
-                        <el-input-number size="mini" v-model="numList[scope.$index]"  :min="0" :max="Number(scope.row.STORE_NUMS)" @change="(val)=>{handleInputNumber(val, scope.row)}"></el-input-number>
-                    </template>
+                      <el-table-column label="商品价格" prop="SELL_PRICE">
+                          <template slot-scope="scope">
+                              <span>{{ Math.round(scope.row.SELL_PRICE * 100) / 100 }}</span>
+                          </template>
+                      </el-table-column>
+                      <el-table-column label="价格PV" prop="PRICE_PV" v-if="goodsCategory === '1'">
+                          <template slot-scope="scope">
+                              <span>{{ Math.round(scope.row.PRICE_PV * 100) / 100 }}</span>
+                          </template>
+                      </el-table-column>
+                      <el-table-column label="库存" prop="STORE_NUMS">
+                      </el-table-column>
 
-                </el-table-column>
-            </el-table>
+                      <el-table-column label="数量"  width="155">
+                        <template slot-scope="scope">
+                          <el-input-number size="mini" v-model="numList[scope.$index]"  :min="0" :max="Number(scope.row.STORE_NUMS)" @change="(val)=>{handleInputNumber(val, scope.row)}"></el-input-number>
+                        </template>
+
+                      </el-table-column>
+                    </el-table>
+                </el-tab-pane>
+            </el-tabs>
             <div class="white-box-footer">
                 <el-button @click="goToAccounts()">去结算</el-button>
                 <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
@@ -54,6 +63,7 @@
         name: "index",
         components: {Pagination},
         mounted() {
+            this.getGoodsActive()
             this.getData()
         },
         data() {
@@ -74,12 +84,20 @@
                 is_go_order:true,
                 numList: [],
                 selectLock:false,
+                goodsCategory: '1',
+                goodsActive: [],
             }
         },
         watch: {
             '$route': function () {
                 this.getData()
-            }
+            },
+            // 监听多选按钮,判断结算按钮是否可用
+            // multipleSelection: function (modern, origin) {
+            //     if (modern.length > 0) {
+            //         this.$data.disabled = false
+            //     }
+            // },
         },
         methods: {
             handleChange(val){
@@ -97,14 +115,14 @@
                 //         this.is_go_order=false
                 //     }
                 // });
-                console.log('this.multipleSelection',this.multipleSelection);
                 setTimeout(()=>{
                     if(this.is_go_order){
                         sessionStorage.setItem('order_goods',JSON.stringify(this.multipleSelection))
+                        sessionStorage.setItem('category_type', this.goodsCategory)
                         this.$router.push({path: `/shop/order`})
                     }
                 },0)
-                 
+
                 // if (rows) {
                 // rows.forEach(row => {
                 //     this.$refs.multipleTable.toggleRowSelection(row);
@@ -172,7 +190,7 @@
             },*/
             getData (page, pageSize) {
                 let obj = this
-                network.getPageData(this, `shop/index`, page, pageSize, this.filterData, function (response) {
+                network.getPageData(this, `shop/index`, page, pageSize, { categoryType: obj.goodsCategory }, function (response) {
                     obj.loading = false;
                     obj.currentPage = response.currentPage;
                     obj.list = response.list;
@@ -207,6 +225,19 @@
 
                 })
             },
+            // 获取商品类型,填充tabs页
+            getGoodsActive() {
+                network.getData(`shop/goods-active`).then(response => {
+                    this.goodsActive = response
+                })
+            },
+            // 切换tab页回调
+            handleClick(tab) {
+                // 切换标签. 查询商品列表,将当期商品分类传入查询条件filter
+                this.goodsCategory = tab.name
+                // 查询商品列表
+                this.getData()
+            },
         }
 
     }
@@ -216,4 +247,4 @@
 .flex{
     display: flex;
 }
-</style>
+</style>

+ 28 - 5
frontendEle/src/views/shop/order-list.vue

@@ -7,20 +7,28 @@
                 <el-table-column label="数量" prop="BUY_NUMS"></el-table-column>
                 <el-table-column label="会员价格">
                     <template slot-scope="props">
-                        {{ props.row.REAL_PRICE * props.row.BUY_NUMS }}
+                        {{ Math.round(props.row.REAL_PRICE * props.row.BUY_NUMS * 100) / 100 }}
                     </template>
                 </el-table-column>
                 <el-table-column label="会员PV">
                     <template slot-scope="props">
-                        {{ props.row.REAL_PV * props.row.BUY_NUMS }}
+                        <span v-if="![4, 5, 6].includes(props.row.CATEGORY_TYPE)">{{ Math.round(props.row.REAL_PV * props.row.BUY_NUMS * 100) / 100 }}</span>
+                        <span v-else>0</span>
                     </template>
                 </el-table-column>
+                <el-table-column label="商品分类" prop="CATEGORY"></el-table-column>
                 <el-table-column label="订单编号" prop="SN"></el-table-column>
                 <el-table-column label="会员编号" prop="USER_NAME"></el-table-column>
                 <el-table-column label="会员姓名" prop="REAL_NAME"></el-table-column>
                 <el-table-column label="收货人" prop="CONSIGNEE"></el-table-column>
                 <el-table-column label="收货电话" prop="MOBILE"></el-table-column>
+                <el-table-column label="地址" prop="FULL_ADDRESS"></el-table-column>
                 <el-table-column label="支付时间" prop="PAY_AT"></el-table-column>
+                <el-table-column label="操作">
+                  <template slot-scope="scope">
+                      <el-button type="primary" size="small" @click.native="handleOrderExportPDF(scope.row.SN)">导出PDF</el-button>
+                  </template>
+                </el-table-column>
             </el-table>
             <div class="white-box-footer">
                 <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
@@ -73,7 +81,9 @@
           obj.columnIndex === 7 ||
           obj.columnIndex === 8 ||
           obj.columnIndex === 9 ||
-          obj.columnIndex === 10
+          obj.columnIndex === 10||
+          obj.columnIndex === 11||
+          obj.columnIndex === 12
         ) {
           // ⼆维数组存储的数据取出
           var _row = this.spanArr[obj.rowIndex];
@@ -97,7 +107,7 @@
           } else {
             //不是第⼀项时,就根据标识去存储
             if (//orderSn,createdAt...是你的第⼀个数据、第⼆个数据...
-
+              // orderList[index].CATEGORY === orderList[index - 1].CATEGORY &&
               orderList[index].ORDER_SN === orderList[index - 1].ORDER_SN &&
               orderList[index].USER_NAME === orderList[index - 1].USER_NAME &&
               orderList[index].REAL_NAME === orderList[index - 1].REAL_NAME &&
@@ -150,9 +160,22 @@
                    // console.log('11111',_this.tableData);
                     _this.getSpanArr(_this.tableData);
 
-
                 });
             },
+            // 导出PDF订单
+            handleOrderExportPDF (orderSn) {
+                network.getData(`shop/order-export/${orderSn}`).then(response => {
+                    let { fileUrl, targetName } = response
+
+                    let downloadElement = document.createElement('a')
+                    downloadElement.target = '_blank'
+                    downloadElement.href = fileUrl
+                    // 下载后文件名
+                    downloadElement.download = targetName
+                    //点击下载
+                    downloadElement.click()
+                })
+            },
         }
     }
 </script>

+ 158 - 60
frontendEle/src/views/shop/order.vue

@@ -17,8 +17,14 @@
                     </el-table-column>
 
                     <el-table-column label="会员价格" prop="member_price">
+                        <template slot-scope="scope">
+                            <span>{{ Math.round(scope.row.member_price * 100) / 100 }}</span>
+                        </template>
                     </el-table-column>
-                    <el-table-column label="会员PV" prop="member_pv">
+                    <el-table-column label="会员PV" prop="member_pv" v-if="category_type === 1">
+                        <template slot-scope="scope">
+                            <span>{{ Math.round(scope.row.member_pv * 100) / 100 }}</span>
+                        </template>
                     </el-table-column>
 <!--                    <el-table-column label="库存" prop="STORE_NUMS">-->
 <!--                    </el-table-column>-->
@@ -26,10 +32,16 @@
                     <el-table-column label="数量" prop="chose_num">
 
                     </el-table-column>
-                    <el-table-column label="会员价格合计金额" prop="member_price_plus">
-
+                    <el-table-column label="合计金额" prop="member_price_plus">
+                        <template slot-scope="scope">
+                            <span>{{ Math.round(scope.row.member_price_plus * 100) / 100 }}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="合计PV" prop="member_pv_plus" v-if="category_type === 1">
+                        <template slot-scope="scope">
+                            <span>{{ Math.round(scope.row.member_pv_plus * 100) / 100 }}</span>
+                        </template>
                     </el-table-column>
-                    <el-table-column label="合计PV" prop="member_pv_plus"></el-table-column>
                 </el-table>
             </div>
             <div class="address_box">
@@ -37,51 +49,82 @@
                 <el-radio-group v-model="addressId" @change='choseAddress'>
                     <div v-for="(item , index) in all_address" :key='index' class="address">
                         <el-radio :label="item.ID" >
-                            {{item.PROVINCE_NAME}}省{{item.CITY_NAME}}市{{item.COUNTY_NAME}}县&nbsp;&nbsp;&nbsp;&nbsp;
-                            详细地址{{item.ADDRESS}}
+                            {{item.PROVINCE_NAME}}省 {{item.CITY_NAME}}市 {{item.COUNTY_NAME}}县&nbsp;&nbsp;&nbsp;&nbsp;
+                            详细地址{{item.ADDRESS}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                             收件人姓名:{{item.CONSIGNEE}}&nbsp;&nbsp;&nbsp;&nbsp;
                             手机号码:{{item.MOBILE}}
                         </el-radio>
                     </div>
+                    <div class="address">
+                      <el-radio label="100000000000000000">自提</el-radio>
+                    </div>
                 </el-radio-group>
             </div>
             <div class="address_box">
                 请选择支付方式:
                 <el-radio-group v-model="payType" @change='chosePayType'>
-                    <div v-for="(item , index) in payList" :key='index' class="address">
-                        <el-radio :label="item.type" >
-                            {{item.name}}
-                        </el-radio>
+                    <div v-for="(item, index) in payList" :key='index' class="address">
+                        <el-radio :label="item.label">{{ item.name }}</el-radio>
                     </div>
                 </el-radio-group>
             </div>
             <div class="box address_box">
-                合计:
+                订单合计:
                 <div class="sum">
-                    <div class="sum_box">
+                    <div class="sum_box" v-if="category_type === 1">
                         <div>运费</div>
-                        <div>¥{{payType=="cash"?freight:pointFreight}}元</div>
+                        <div><span v-if="category_type === 1">{{ prefixSign }}</span> {{ payType === "cash" ? freight : pointFreight }} <span v-if="category_type === 1">{{ unit }}</span></div>
                     </div>
                     <div class="sum_box">
                         <div>实付金额</div>
-                        <div>¥{{payType=="cash"?cashSum:pointsSum}}元</div>
+                        <div><span v-if="category_type === 1">{{ prefixSign }}</span> {{ payType === "cash" ? cashSum : pointsSum }} <span v-if="category_type === 1">{{ unit }}</span></div>
                     </div>
-                    <div class="sum_box">
-                        <div>账户积分</div>
-                        <div>{{balance.points}}</div>
+                </div>
+            </div>
+
+            <div class="box address_box">
+                账户余额:
+                <div class="sum">
+                    <div v-if="category_type === 1">
+<!--                        <div class="sum_box">-->
+<!--                            <div>账户积分</div>-->
+<!--                            <div>{{ balance.points }}</div>-->
+<!--                        </div>-->
+                        <div class="sum_box">
+                            <div>账户余额</div>
+                            <div>¥{{ balance.cash }}元</div>
+                        </div>
+                        <div class="sum_box">
+                            <div>兑换点数</div>
+                            <div>{{ balance.exchange }}</div>
+                        </div>
                     </div>
-                    <div class="sum_box">
-                        <div>账户余额</div>
-                        <div>¥{{balance.cash}}元</div>
+
+                    <div v-if="category_type === 4">
+                        <div class="sum_box">
+                            <div>旅游积分</div>
+                            <div>{{ balance.travel_points }}</div>
+                        </div>
                     </div>
-                    <div class="sum_box">
-                        <div>无业绩兑换券</div>
-                        <div>{{balance.exchange}}</div>
+
+                    <div v-if="category_type === 5">
+                        <div class="sum_box">
+                            <div>名车积分</div>
+                            <div>{{ balance.car_points }}</div>
+                        </div>
+                    </div>
+
+                    <div v-if="category_type === 6">
+                        <div class="sum_box">
+                            <div>豪宅积分</div>
+                            <div>{{ balance.house_points }}</div>
+                        </div>
                     </div>
                 </div>
             </div>
+
             <div>
-                <el-button @click="goToAccounts()" :loading="submitButtonStat">去结算</el-button>
+                <el-button type="primary" @click="goToAccounts()" :loading="submitButtonStat">去结算</el-button>
             </div>
         </div>
     </div>
@@ -101,6 +144,7 @@
                 balance:{},
                 addressId:'',
                 payType:'',
+                payTypeId: '',
                 pointsSum:'',
                 cashSum:'',
                 freight:'',
@@ -109,14 +153,18 @@
                 goodsNum:'',
                 payPassword:'',
                 submitButtonStat:false,
+                category_type: '',
+                prefixSign: '¥',
+                unit: '元',
             }
         },
         created(){
-            this.getShowCart();
             let option= sessionStorage.getItem('order_goods');
+            this.category_type = parseInt(sessionStorage.getItem('category_type'))
+            this.getShowCart();
             if(option){
                 let pageGoodsList=JSON.parse(option);
-                console.log(pageGoodsList);
+                // console.log(pageGoodsList);
                 let pageList;
                 for( let i in pageGoodsList ) {
                     pageList =  pageGoodsList[i];
@@ -125,11 +173,11 @@
                     pageList.map((pageData, index)=>{
                         if( Number(pageData.chose_num) > 0 ) {
                             let discount = pageData.DISCOUNT / 100;
-                            pageData.member_price = pageData.SELL_PRICE * discount;
-                            pageData.member_price_plus = pageData.SELL_PRICE * Number(pageData.chose_num) * discount;
+                            pageData.member_price = Math.round(pageData.SELL_PRICE * discount * 100) / 100;
+                            pageData.member_price_plus = Math.round(pageData.SELL_PRICE * Number(pageData.chose_num) * discount * 100) / 100;
 
-                            pageData.member_pv = pageData.PRICE_PV * discount;
-                            pageData.member_pv_plus = pageData.PRICE_PV * Number(pageData.chose_num) * discount;
+                            pageData.member_pv = Math.round(pageData.PRICE_PV * discount * 100) / 100;
+                            pageData.member_pv_plus = Math.round(pageData.PRICE_PV * Number(pageData.chose_num) * discount * 100) / 100;
 
                             this.goods.push(pageData)
                         }
@@ -140,6 +188,11 @@
             }
         },
         methods:{
+            setFreight(){
+              if(this.addressId=='100000000000000000'){//如果地址为自提,则运费为0
+                this.pointFreight = this.freight = 0;
+              }
+            },
             getSummaries(param) {
               const { columns, data } = param;
               const sums = [];
@@ -153,9 +206,9 @@
                   sums[index] = values.reduce((prev, curr) => {
                     const value = Number(curr);
                     if (!isNaN(value)) {
-                      return prev + curr;
+                      return Math.round((prev + curr) * 100) / 100;
                     } else {
-                      return prev;
+                      return Math.round(prev * 100) / 100;
                     }
                   }, 0);
                 }
@@ -164,6 +217,37 @@
               return sums;
             },
             goToAccounts(){
+                let amountBalance = 0
+                // 前置判断余额是否够支付
+                if (this.category_type === 1) {
+                    amountBalance = (this.payType === 'cash') ? this.balance.cash : this.balance.exchange
+                } else if (this.category_type === 4) {
+                    amountBalance = this.balance.travel_points
+                } else if (this.category_type === 5) {
+                    amountBalance = this.balance.car_points
+                } else if (this.category_type === 6) {
+                    amountBalance = this.balance.house_points
+                }
+
+                // 提示信息
+                let tips = '余额'
+                if (this.payType !== 'cash') {
+                    let payObj = this.payList.find((item) => {
+                        return item.label === this.payType
+                    })
+                    tips = (payObj.length <= 0) ? '' : payObj.name
+                }
+
+                if ((amountBalance - this.cashSum) < 0) {
+                    let tips = this.payList[this.payType] ? this.payList[this.payType].label : '余额'
+                    this.$message({
+                        message: tips + '不足,无法购买商品',
+                        type: 'error'
+                    })
+                    this.submitButtonStat = false
+                    return false
+                }
+
                 this.submitButtonStat = true
                 // let path = 'sure-order'
                 this.$prompt('请输入支付密码', '提示', {
@@ -174,7 +258,14 @@
                     inputErrorMessage: '请输入支付密码'
                 }).then(({value}) => {
                     this.payPassword = value
-                    return network.postData('shop/sure-order',{addressId:this.addressId,payType:this.payType,goodsId:this.goodsId,goodsNum:this.goodsNum,payPassword: this.payPassword}).then(response => {
+                    let data = {
+                        addressId: this.addressId,
+                        payType: this.payType,
+                        goodsId: this.goodsId,
+                        goodsNum: this.goodsNum,
+                        payPassword: this.payPassword
+                    }
+                    return network.postData('shop/sure-order',data).then(response => {
                         this.$message({
                             message: response,
                             type: 'success'
@@ -188,11 +279,9 @@
                     }).catch((response) => {
                         this.submitButtonStat = false
                     })
-
+                }).catch(() => {
+                    this.submitButtonStat = false
                 })
-
-
-
             },
             getSumMoney(){
                 // let points_plus_sum=[];
@@ -215,10 +304,14 @@
                 let payAmount = tool.sum(cash_plus_sum);
                 // let payPointAmount = tool.sum(points_plus_sum);
 
-                if(payAmount>=300){
-                  this.pointFreight = this.freight = 0;
-                }else{
-                  this.pointFreight = this.freight = 15;
+                // 只有普通商品有运费
+                if (this.category_type === 1) {
+                    if(payAmount>=300){
+                        this.pointFreight = this.freight = 0;
+                    }else{
+                        this.pointFreight = this.freight = 15;
+                    }
+                    this.setFreight();
                 }
                 // if(payPointAmount>=300){
                 //     this.pointFreight = 0;
@@ -228,37 +321,42 @@
                 //console.log('points_plus_sum',points_plus_sum);
                 //console.log('cash_plus_sum',cash_plus_sum);
                 // this.pointsSum=tool.formatPrice(tool.sum(points_plus_sum) + this.pointFreight);
+              console.log(this.freight)
               this.pointsSum = this.cashSum = tool.formatPrice(tool.sum(cash_plus_sum) + this.freight) ;
             },
             getShowCart(){
-                network.getData('shop/show-cart')
-                .then(response=>{
-                    this.loading=false;
-                    // console.log(response);
-                    this.all_address=response.allAddress;
+                network.getData('shop/show-cart', { categoryType: this.categoryType })
+                .then(response => {
+                    this.loading = false
+                    // 收货地址
+                    this.all_address = response.allAddress;
                     this.all_address.map((item,index)=>{
                         if(item.IS_DEFAULT==1){
-                            this.addressId=item.ID
+                            this.addressId = item.ID
                         }
                     })
-                    for(let key in response.payList){
-                        this.payList.push({type:key,name:response.payList[key].name})
+                    // 账户
+                    this.balance = response.userBalance
+
+                    // 支付方式
+                    for (let item of response.sellType) {
+                        if (item.id === this.category_type) {
+                            this.payList = item.sell_type
+                            break
+                        }
                     }
-                    // console.log(this.payList)
-                    // for(let key in response.userBalance){
-                    //     this.balance.push({type:key,own_price:response.userBalance[key]})
-                    // }
-                    this.balance=response.userBalance;
-                    this.payType=this.payList[0].type;//默认设置为第一项付款方式
-                   // console.log(this.balance)
+
+                    // 支付方式的第一项默认选中
+                    this.payType = this.payList[0]
                 })
             },
-            chosePayType(type){
-                console.log(type);
-                console.log(this.payType);
+            // 切换支付方式
+            chosePayType(type) {
+                this.payType = type
             },
             choseAddress(addressId){
-                console.log(addressId);
+              this.getSumMoney()
+                // console.log(addressId);
             }
         }
     }

+ 5 - 5
frontendEle/src/views/shop/reconsume-order.vue

@@ -26,7 +26,7 @@
                     <el-table-column label="数量" prop="chose_num">
 
                     </el-table-column>
-                    <el-table-column label="会员价格合计金额" prop="member_price_plus">
+                    <el-table-column label="合计金额" prop="member_price_plus">
 
                     </el-table-column>
                     <el-table-column label="合计PV" prop="member_pv_plus"></el-table-column>
@@ -196,11 +196,11 @@
                     pageList.map((pageData, index)=>{
                         if( Number(pageData.chose_num) > 0 ) {
                             let discount = pageData.DISCOUNT / 100;
-                            pageData.member_price = pageData.SELL_PRICE * discount;
-                            pageData.member_price_plus = pageData.SELL_PRICE * Number(pageData.chose_num) * discount;
+                            pageData.member_price = Math.round(pageData.SELL_PRICE * discount * 100) / 100;
+                            pageData.member_price_plus = Math.round(pageData.SELL_PRICE * Number(pageData.chose_num) * discount * 100) / 100;
 
-                            pageData.member_pv = pageData.PRICE_PV * discount;
-                            pageData.member_pv_plus = pageData.PRICE_PV * Number(pageData.chose_num) * discount;
+                            pageData.member_pv = Math.round(pageData.PRICE_PV * discount * 100) / 100;
+                            pageData.member_pv_plus = Math.round(pageData.PRICE_PV * Number(pageData.chose_num) * discount * 100) / 100;
 
                             this.goods.push(pageData)
                         }

+ 24 - 4
frontendEle/src/views/user/dec.vue

@@ -185,11 +185,21 @@
                     </template>
                     <el-input v-model="form.acceptMobile"></el-input>
                 </el-form-item>
+                <el-form-item>
+                    <template slot="label">
+                      收货方式
+                    </template>
+                    <el-radio-group v-model="form.way" @change="wayChange">
+                      <el-radio label="express">快递</el-radio>
+                      <el-radio label="pickup">自提</el-radio>
+                    </el-radio-group>
+                </el-form-item>
                 <el-form-item prop="areaSelected">
                     <template slot="label">
                         地区
                     </template>
                     <el-cascader
+                            :disabled="areaDisabled"
                             size="large"
                             :options="regionData"
                             v-model="form.areaSelected">
@@ -199,7 +209,7 @@
                     <template slot="label">
                         详细地址
                     </template>
-                    <el-input v-model="form.address"></el-input>
+                    <el-input :disabled="addressDisabled" v-model="form.address"></el-input>
                 </el-form-item>
 
                 <div class="hr-tip"><span>银行信息</span></div>
@@ -292,8 +302,7 @@
                     province:'',
                     city:'',
                     county:'',
-
-
+                    way:"express"
                 },
                 conRealName: '-',
                 recRealName: '-',
@@ -311,10 +320,21 @@
                 goodsNums:[],
                 numList: [],
                 sell_price_sum:0.00,
-                price_pv_sum:0.00
+                price_pv_sum:0.00,
+                areaDisabled: false,
+                addressDisabled: false
             }
         },
         methods: {
+            wayChange(){
+              if(this.form.way==='pickup'){
+                this.areaDisabled = true
+                this.addressDisabled = true
+              }else{
+                this.areaDisabled = false
+                this.addressDisabled = false
+              }
+            },
             getSum(){
                 let sell_price_sum=0,price_pv_sum=0;
                 this.multipleSelection.map((item,index)=>{

+ 0 - 16
vendor/bower-asset/typeahead.js/.gitignore

@@ -1,16 +0,0 @@
-*.swp
-.DS_Store
-
-.grunt
-_SpecRunner.html
-test/coverage
-
-dist_temp
-
-node_modules
-npm-debug.log
-
-bower_components
-
-*.iml
-.idea

+ 0 - 16
vendor/bower-asset/typeahead.js/.jshintrc

@@ -1,16 +0,0 @@
-{
-  "curly": true,
-  "newcap": true,
-  "noarg": true,
-  "quotmark": "single",
-  "regexp": true,
-  "trailing": true,
-
-  "boss": true,
-  "eqnull": true,
-  "expr": true,
-  "validthis": true,
-  
-  "browser": true,
-  "jquery": true
-}

+ 0 - 29
vendor/bower-asset/typeahead.js/.travis.yml

@@ -1,29 +0,0 @@
-language: node_js
-env: 
-  matrix: 
-  - TEST_SUITE=unit
-  - TEST_SUITE=integration BROWSER='firefox'
-  - TEST_SUITE=integration BROWSER='firefox:3.5'
-  - TEST_SUITE=integration BROWSER='firefox:3.6'
-  - TEST_SUITE=integration BROWSER='safari:5'
-  - TEST_SUITE=integration BROWSER='safari:6'
-  - TEST_SUITE=integration BROWSER='safari:7'
-  - TEST_SUITE=integration BROWSER='internet explorer:8'
-  - TEST_SUITE=integration BROWSER='internet explorer:9'
-  - TEST_SUITE=integration BROWSER='internet explorer:10'
-  - TEST_SUITE=integration BROWSER='internet explorer:11'
-  - TEST_SUITE=integration BROWSER='chrome'
-  global: 
-  - secure: VY4J2ERfrMEin++f4+UDDtTMWLuE3jaYAVchRxfO2c6PQUYgR+SW4SMekz855U/BuptMtiVMR2UUoNGMgOSKIFkIXpPfHhx47G5a541v0WNjXfQ2qzivXAWaXNK3l3C58z4dKxgPWsFY9JtMVCddJd2vQieAILto8D8G09p7bpo=
-  - secure: kehbNCoYUG2gLnhmCH/oKhlJG6LoxgcOPMCtY7KOI4ropG8qlypb+O2b/19+BWeO3aIuMB0JajNh3p2NL0UKgLmUK7EYBA9fQz+vesFReRk0V/KqMTSxHJuseM4aLOWA2Wr9US843VGltfODVvDN5sNrfY7RcoRx2cTK/k1CXa8=
-node_js: 
-- 0.11.13
-before_script: 
-- npm install -g grunt-cli@0.1.13
-- npm install -g node-static@0.7.3
-- npm install -g bower@1.3.8
-- bower install
-- grunt build
-script: test/ci
-addons:
-  sauce_connect: true

+ 0 - 249
vendor/bower-asset/typeahead.js/CHANGELOG.md

@@ -1,249 +0,0 @@
-Changelog
-=========
-
-For transparency and insight into our release cycle, releases will be numbered 
-with the follow format:
-
-`<major>.<minor>.<patch>`
-
-And constructed with the following guidelines:
-
-* Breaking backwards compatibility bumps the major
-* New additions without breaking backwards compatibility bumps the minor
-* Bug fixes and misc changes bump the patch
-
-For more information on semantic versioning, please visit http://semver.org/.
-
----
-
-### 0.11.1 April 26, 2015
-
-* Add prepare option to prefetch. [#1181]
-* Handle QuotaExceededError. [#1110]
-* Escape HTML entities from suggestion display value when rendering with default
-  template. [#964]
-* List jquery as a dependency in package.json. [#1143]
-
-### 0.11.0 April 25, 2015
-
-An overhaul of typeahead.js – consider this a release candidate for v1. There
-are bunch of API changes with this release so don't expect backwards 
-compatibility with previous versions. There are also many new undocumented 
-features that have been introduced. Documentation for those features will be 
-added before v1 ships.
-
-Beware that since this release is pretty much a rewrite, there are bound to be
-some bugs. To be safe, you should consider this release beta software and 
-throughly test your integration of it before using it in production 
-environments. This caveat only applies to this release as subsequent releases
-will address any issues that come up.
-
-### 0.10.5 August 7, 2014
-
-* Increase supported version range for jQuery dependency. [#917]
-
-### 0.10.4 July 13, 2014
-
-**Hotfix**
-
-* Fix regression that breaks Bloodhound instances when more than 1 instance is
-  relying on remote data. [#899]
-
-### 0.10.3 July 10, 2014
-
-**Bug fixes**
-
-* `Bloodhound#clearPrefetchCache` now works with cache keys that contain regex 
-  characters. [#771]
-* Prevent outdated network requests from being sent. [#809]
-* Add support to object tokenizers for multiple property tokenization. [#811]
-* Fix broken `jQuery#typeahead('val')` method. [#815]
-* Remove `disabled` attribute from the hint input control. [#839]
-* Add `tt-highlight` class to highlighted text. [#833]
-* Handle non-string types that are passed to `jQuery#typeahead('val', val)`. [#881]
-
-### 0.10.2 March 10, 2014
-
-* Prevent flickering of dropdown menu when requesting remote suggestions. [#718]
-* Reduce hint flickering. [#754]
-* Added `Bloodhound#{clear, clearPrefetchCache, clearRemoteCache}` and made it
-  possible to reinitialize Bloodhound instances. [#703]
-* Invoke `local` function during initialization. [#687]
-* In addition to HTML strings, templates can now return DOM nodes. [#742]
-* Prevent `jQuery#typeahead('val', val)` from opening dropdown menus of 
-  non-active typeaheads. [#646]
-* Fix bug in IE that resulted in dropdown menus with overflow being closed
-  when clicking on the scrollbar. [#705]
-* Only show dropdown menu if `minLength` is satisfied. [#710]
-
-### 0.10.1 February 9, 2014
-
-**Hotfix**
-
-* Fixed bug that prevented some ajax configs from being respected. [#630]
-* Event delegation on suggestion clicks is no longer broken. [#118]
-* Ensure dataset names are valid class name suffixes. [#610]
-* Added support for `displayKey` to be a function. [#633]
-* `jQuery#typeahead('val')` now mirrors `jQuery#val()`. [#659]
-* Datasets can now be passed to jQuery plugin as an array. [#664]
-* Added a `noConflict` method to the jQuery plugin. [#612]
-* Bloodhound's `local` property can now be a function. [#485]
-
-### 0.10.0 February 2, 2014
-
-**Introducting Bloodhound**
-
-This release was almost a complete rewrite of typeahead.js and will hopefully
-lay the foundation for the 1.0.0 release. It's impossible to enumerate all of 
-the issues that were fixed. If you want to get an idea of what issues 0.10.0 
-resolved, take a look at the closed issues in the [0.10.0 milestone].
-
-The most important change in 0.10.0 is that typeahead.js was broken up into 2 
-individual components: Bloodhound and jQuery#typeahead. Bloodhound is an 
-feature-rich suggestion engine. jQuery#typeahead is a jQuery plugin that turns
-input controls into typeaheads.
-
-It's impossible to write a typeahead library that supports every use-case out 
-of the box – that was the main motivation behind decomposing typeahead.js. 
-Previously, some prospective typeahead.js users were unable to use the library 
-because either the suggestion engine or the typeahead UI did not meet their
-requirements. In those cases, they were either forced to fork typeahead.js and
-make the necessary modifications or they had to give up on using typeahead.js
-entirely. Now they have the option of swapping out the component that doesn't 
-work for them with a custom implementation.
-
-### 0.9.3 June 24, 2013
-
-* Ensure cursor visibility in menus with overflow. [#209]
-* Fixed bug that led to the menu staying open when it should have been closed. [#260]
-* Private browsing in Safari no longer breaks prefetch. [#270]
-* Pressing tab while a suggestion is highlighted now results in a selection. [#266]
-* Dataset name is now passed as an argument for typeahead:selected event. [#207]
-
-### 0.9.2 April 14, 2013
-
-* Prefetch usage no longer breaks when cookies are disabled. [#190]
-* Precompiled templates are now wrapped in the appropriate DOM element. [#172]
-
-### 0.9.1 April 1, 2013
-
-* Multiple requests no longer get sent for a query when datasets share a remote source. [#152]
-* Datasets now support precompiled templates. [#137]
-* Cached remote suggestions now get rendered immediately. [#156]
-* Added typeahead:autocompleted event. [#132]
-* Added a plugin method for programmatically setting the query. Experimental. [#159]
-* Added minLength option for datasets. Experimental. [#131]
-* Prefetch objects now support thumbprint option. Experimental. [#157]
-
-### 0.9.0 March 24, 2013
-
-**Custom events, no more typeahead.css, and an improved API**
-
-* Implemented the triggering of custom events. [#106]
-* Got rid of typeahead.css and now apply styling through JavaScript. [#15]
-* Made the API more flexible and addressed a handful of remote issues by rewriting the transport component. [#25]
-* Added support for dataset headers and footers. [#81]
-* No longer cache unnamed datasets. [#116]
-* Made the key name of the value property configurable. [#115]
-* Input values set before initialization of typeaheads are now respected. [#109]
-* Fixed an input value/hint casing bug. [#108]
-
-### 0.8.2 March 04, 2013
-
-* Fixed bug causing error to be thrown when initializing a typeahead on multiple elements. [#51]
-* Tokens with falsy values are now filtered out – was causing wonky behavior. [#75]
-* No longer making remote requests for blank queries. [#74]
-* Datums with regex characters in their value no longer cause errors. [#77]
-* Now compatible with the Closure Compiler. [#48]
-* Reference to jQuery is now obtained through window.jQuery, not window.$. [#47]
-* Added a plugin method for destroying typeaheads. Won't be documented until v0.9 and might change before then. [#59]
-
-### 0.8.1 February 25, 2013
-
-* Fixed bug preventing local and prefetch from being used together. [#39]
-* No longer prevent default browser behavior when up or down arrow is pressed with a modifier. [#6]
-* Hint is hidden when user entered query is wider than the input. [#26]
-* Data stored in localStorage now expires properly. [#34]
-* Normalized search tokens and fixed query tokenization. [#38]
-* Remote suggestions now are appended, not prepended to suggestions list. [#40]
-* Fixed some typos through the codebase. [#3]
-
-### 0.8.0 February 19, 2013
-
-**Initial public release**
-
-* Prefetch and search data locally insanely fast.
-* Search hard-coded, prefetched, and/or remote data.
-* Hinting.
-* RTL/IME/international support.
-* Search multiple datasets.
-* Share datasets (and caching) between multiple inputs.
-* And much, much more...
-
-[0.10.0 milestone]: https://github.com/twitter/typeahead.js/issues?milestone=8&page=1&state=closed
-
-[#1181]: https://github.com/twitter/typeahead.js/pull/1181
-[#1143]: https://github.com/twitter/typeahead.js/pull/1143
-[#1110]: https://github.com/twitter/typeahead.js/pull/1110
-[#964]: https://github.com/twitter/typeahead.js/pull/964
-[#917]: https://github.com/twitter/typeahead.js/pull/917
-[#899]: https://github.com/twitter/typeahead.js/pull/899
-[#881]: https://github.com/twitter/typeahead.js/pull/881
-[#839]: https://github.com/twitter/typeahead.js/pull/839
-[#833]: https://github.com/twitter/typeahead.js/pull/833
-[#815]: https://github.com/twitter/typeahead.js/pull/815
-[#811]: https://github.com/twitter/typeahead.js/pull/811
-[#809]: https://github.com/twitter/typeahead.js/pull/809
-[#771]: https://github.com/twitter/typeahead.js/pull/771
-[#754]: https://github.com/twitter/typeahead.js/pull/754
-[#742]: https://github.com/twitter/typeahead.js/pull/742
-[#718]: https://github.com/twitter/typeahead.js/pull/718
-[#710]: https://github.com/twitter/typeahead.js/pull/710
-[#705]: https://github.com/twitter/typeahead.js/pull/705
-[#703]: https://github.com/twitter/typeahead.js/pull/703
-[#687]: https://github.com/twitter/typeahead.js/pull/687
-[#664]: https://github.com/twitter/typeahead.js/pull/664
-[#659]: https://github.com/twitter/typeahead.js/pull/659
-[#646]: https://github.com/twitter/typeahead.js/pull/646
-[#633]: https://github.com/twitter/typeahead.js/pull/633
-[#630]: https://github.com/twitter/typeahead.js/pull/630
-[#612]: https://github.com/twitter/typeahead.js/pull/612
-[#610]: https://github.com/twitter/typeahead.js/pull/610
-[#485]: https://github.com/twitter/typeahead.js/pull/485
-[#270]: https://github.com/twitter/typeahead.js/pull/270
-[#266]: https://github.com/twitter/typeahead.js/pull/266
-[#260]: https://github.com/twitter/typeahead.js/pull/260
-[#209]: https://github.com/twitter/typeahead.js/pull/209
-[#207]: https://github.com/twitter/typeahead.js/pull/207
-[#190]: https://github.com/twitter/typeahead.js/pull/190
-[#172]: https://github.com/twitter/typeahead.js/pull/172
-[#159]: https://github.com/twitter/typeahead.js/pull/159
-[#157]: https://github.com/twitter/typeahead.js/pull/157
-[#156]: https://github.com/twitter/typeahead.js/pull/156
-[#152]: https://github.com/twitter/typeahead.js/pull/152
-[#137]: https://github.com/twitter/typeahead.js/pull/137
-[#132]: https://github.com/twitter/typeahead.js/pull/132
-[#131]: https://github.com/twitter/typeahead.js/pull/131
-[#118]: https://github.com/twitter/typeahead.js/pull/118
-[#116]: https://github.com/twitter/typeahead.js/pull/116
-[#115]: https://github.com/twitter/typeahead.js/pull/115
-[#109]: https://github.com/twitter/typeahead.js/pull/109
-[#108]: https://github.com/twitter/typeahead.js/pull/108
-[#106]: https://github.com/twitter/typeahead.js/pull/106
-[#81]: https://github.com/twitter/typeahead.js/pull/81
-[#77]: https://github.com/twitter/typeahead.js/pull/77
-[#75]: https://github.com/twitter/typeahead.js/pull/75
-[#74]: https://github.com/twitter/typeahead.js/pull/74
-[#59]: https://github.com/twitter/typeahead.js/pull/59
-[#51]: https://github.com/twitter/typeahead.js/pull/51
-[#48]: https://github.com/twitter/typeahead.js/pull/48
-[#47]: https://github.com/twitter/typeahead.js/pull/47
-[#40]: https://github.com/twitter/typeahead.js/pull/40
-[#39]: https://github.com/twitter/typeahead.js/pull/39
-[#38]: https://github.com/twitter/typeahead.js/pull/38
-[#34]: https://github.com/twitter/typeahead.js/pull/34
-[#26]: https://github.com/twitter/typeahead.js/pull/26
-[#25]: https://github.com/twitter/typeahead.js/pull/25
-[#15]: https://github.com/twitter/typeahead.js/pull/15
-[#6]: https://github.com/twitter/typeahead.js/pull/6
-[#3]: https://github.com/twitter/typeahead.js/pull/3

+ 0 - 120
vendor/bower-asset/typeahead.js/CONTRIBUTING.md

@@ -1,120 +0,0 @@
-Contributing to typeahead.js
-============================
-
-*These contributing guidelines were proudly stolen from the 
-[Flight](https://github.com/flightjs/flight) project*
-
-Looking to contribute something to typeahead.js? Here's how you can help.
-
-Bugs Reports
-------------
-
-A bug is a _demonstrable problem_ that is caused by the code in the
-repository. Good bug reports are extremely helpful – thank you!
-
-Guidelines for bug reports:
-
-1. **Use the GitHub issue search** &mdash; check if the issue has already been
-   reported.
-
-2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
-   latest `master` or integration branch in the repository.
-
-3. **Isolate the problem** &mdash; ideally create a reduced test
-   case and a live example.
-
-4. Please try to be as detailed as possible in your report. Include specific
-   information about the environment – operating system and version, browser
-   and version, version of typeahead.js – and steps required to reproduce the 
-  issue.
-
-Feature Requests & Contribution Enquiries
------------------------------------------
-
-Feature requests are welcome. But take a moment to find out whether your idea
-fits with the scope and aims of the project. It's up to *you* to make a strong
-case for the inclusion of your feature. Please provide as much detail and
-context as possible.
-
-Contribution enquiries should take place before any significant pull request,
-otherwise you risk spending a lot of time working on something that we might
-have good reasons for rejecting.
-
-Pull Requests
--------------
-
-Good pull requests – patches, improvements, new features – are a fantastic
-help. They should remain focused in scope and avoid containing unrelated
-commits.
-
-Make sure to adhere to the coding conventions used throughout the codebase
-(indentation, accurate comments, etc.) and any other requirements (such as test
-coverage).
-
-Please follow this process; it's the best way to get your work included in the
-project:
-
-1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
-   and configure the remotes:
-
-   ```bash
-   # Clone your fork of the repo into the current directory
-   git clone https://github.com/<your-username>/typeahead.js
-   # Navigate to the newly cloned directory
-   cd <repo-name>
-   # Assign the original repo to a remote called "upstream"
-   git remote add upstream git://github.com/twitter/typeahead.js
-   ```
-
-2. If you cloned a while ago, get the latest changes from upstream:
-
-   ```bash
-   git checkout master
-   git pull upstream master
-   ```
-
-3. Install the dependencies (you must have Node.js and [Bower](http://bower.io)
-   installed), and create a new topic branch (off the main project development
-   branch) to contain your feature, change, or fix:
-
-   ```bash
-   npm install
-   bower install
-   git checkout -b <topic-branch-name>
-   ```
-
-4. Make sure to update, or add to the tests when appropriate. Patches and
-   features will not be accepted without tests. Run `npm test` to check that
-   all tests pass after you've made changes.
-
-5. Commit your changes in logical chunks. Provide clear and explanatory commit
-   messages. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up
-   your commits before making them public.
-
-6. Locally merge (or rebase) the upstream development branch into your topic branch:
-
-   ```bash
-   git pull [--rebase] upstream master
-   ```
-
-7. Push your topic branch up to your fork:
-
-   ```bash
-   git push origin <topic-branch-name>
-   ```
-
-8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
-    with a clear title and description.
-
-9. If you are asked to amend your changes before they can be merged in, please
-   use `git commit --amend` (or rebasing for multi-commit Pull Requests) and
-   force push to your remote feature branch. You may also be asked to squash
-   commits.
-
-License
--------
-
-By contributing your code,
-
-You agree to license your contribution under the terms of the MIT License
-https://github.com/twitter/typeahead.js/blob/master/LICENSE

+ 0 - 330
vendor/bower-asset/typeahead.js/Gruntfile.js

@@ -1,330 +0,0 @@
-var semver = require('semver'),
-    f = require('util').format,
-    files = {
-      common: [
-      'src/common/utils.js'
-      ],
-      bloodhound: [
-      'src/bloodhound/version.js',
-      'src/bloodhound/tokenizers.js',
-      'src/bloodhound/lru_cache.js',
-      'src/bloodhound/persistent_storage.js',
-      'src/bloodhound/transport.js',
-      'src/bloodhound/search_index.js',
-      'src/bloodhound/prefetch.js',
-      'src/bloodhound/remote.js',
-      'src/bloodhound/options_parser.js',
-      'src/bloodhound/bloodhound.js'
-      ],
-      typeahead: [
-      'src/typeahead/www.js',
-      'src/typeahead/event_bus.js',
-      'src/typeahead/event_emitter.js',
-      'src/typeahead/highlight.js',
-      'src/typeahead/input.js',
-      'src/typeahead/dataset.js',
-      'src/typeahead/menu.js',
-      'src/typeahead/default_menu.js',
-      'src/typeahead/typeahead.js',
-      'src/typeahead/plugin.js'
-      ]
-    };
-
-module.exports = function(grunt) {
-  grunt.initConfig({
-    version: grunt.file.readJSON('package.json').version,
-
-    tempDir: 'dist_temp',
-    buildDir: 'dist',
-
-    banner: [
-      '/*!',
-      ' * typeahead.js <%= version %>',
-      ' * https://github.com/twitter/typeahead.js',
-      ' * Copyright 2013-<%= grunt.template.today("yyyy") %> Twitter, Inc. and other contributors; Licensed MIT',
-      ' */\n\n'
-    ].join('\n'),
-
-    uglify: {
-      options: {
-        banner: '<%= banner %>'
-      },
-
-      concatBloodhound: {
-        options: {
-          mangle: false,
-          beautify: true,
-          compress: false,
-          banner: ''
-        },
-        src: files.common.concat(files.bloodhound),
-        dest: '<%= tempDir %>/bloodhound.js'
-      },
-      concatTypeahead: {
-        options: {
-          mangle: false,
-          beautify: true,
-          compress: false,
-          banner: ''
-        },
-        src: files.common.concat(files.typeahead),
-        dest: '<%= tempDir %>/typeahead.jquery.js'
-      },
-
-      bloodhound: {
-        options: {
-          mangle: false,
-          beautify: true,
-          compress: false
-        },
-        src: '<%= tempDir %>/bloodhound.js',
-        dest: '<%= buildDir %>/bloodhound.js'
-      },
-      bloodhoundMin: {
-        options: {
-          mangle: true,
-          compress: {}
-        },
-        src: '<%= tempDir %>/bloodhound.js',
-        dest: '<%= buildDir %>/bloodhound.min.js'
-      },
-      typeahead: {
-        options: {
-          mangle: false,
-          beautify: true,
-          compress: false
-        },
-        src: '<%= tempDir %>/typeahead.jquery.js',
-        dest: '<%= buildDir %>/typeahead.jquery.js'
-      },
-      typeaheadMin: {
-        options: {
-          mangle: true,
-          compress: {}
-        },
-        src: '<%= tempDir %>/typeahead.jquery.js',
-        dest: '<%= buildDir %>/typeahead.jquery.min.js'
-      },
-      bundle: {
-        options: {
-          mangle: false,
-          beautify: true,
-          compress: false
-        },
-        src: [
-          '<%= tempDir %>/bloodhound.js',
-          '<%= tempDir %>/typeahead.jquery.js'
-        ],
-        dest: '<%= buildDir %>/typeahead.bundle.js'
-
-      },
-      bundleMin: {
-        options: {
-          mangle: true,
-          compress: {}
-        },
-        src: [
-          '<%= tempDir %>/bloodhound.js',
-          '<%= tempDir %>/typeahead.jquery.js'
-        ],
-        dest: '<%= buildDir %>/typeahead.bundle.min.js'
-      }
-    },
-
-    umd: {
-      bloodhound: {
-        src: '<%= tempDir %>/bloodhound.js',
-        objectToExport: 'Bloodhound',
-        amdModuleId: 'bloodhound',
-        deps: {
-          default: ['$'],
-          amd: ['jquery'],
-          cjs: ['jquery'],
-          global: ['jQuery']
-        }
-      },
-      typeahead: {
-        src: '<%= tempDir %>/typeahead.jquery.js',
-        amdModuleId: 'typeahead.js',
-        deps: {
-          default: ['$'],
-          amd: ['jquery'],
-          cjs: ['jquery'],
-          global: ['jQuery']
-        }
-      }
-    },
-
-    sed: {
-      version: {
-        pattern: '%VERSION%',
-        replacement: '<%= version %>',
-        recursive: true,
-        path: '<%= buildDir %>'
-      }
-    },
-
-    jshint: {
-      options: {
-        jshintrc: '.jshintrc'
-      },
-      src: 'src/**/*.js',
-      test: ['test/**/*_spec.js', 'test/integration/test.js'],
-      gruntfile: ['Gruntfile.js']
-    },
-
-    watch: {
-      js: {
-        files: 'src/**/*',
-        tasks: 'build'
-      }
-    },
-
-    exec: {
-      npm_publish: 'npm publish',
-      git_is_clean: 'test -z "$(git status --porcelain)"',
-      git_on_master: 'test $(git symbolic-ref --short -q HEAD) = master',
-      git_add: 'git add .',
-      git_push: 'git push && git push --tags',
-      git_commit: {
-        cmd: function(m) { return f('git commit -m "%s"', m); }
-      },
-      git_tag: {
-        cmd: function(v) { return f('git tag v%s -am "%s"', v, v); }
-      },
-      publish_assets: [
-        'cp -r <%= buildDir %> typeahead.js',
-        'zip -r typeahead.js/typeahead.js.zip typeahead.js',
-        'git checkout gh-pages',
-        'rm -rf releases/latest',
-        'cp -r typeahead.js releases/<%= version %>',
-        'cp -r typeahead.js releases/latest',
-        'git add releases/<%= version %> releases/latest',
-        'sed -E -i "" \'s/v[0-9]+\\.[0-9]+\\.[0-9]+/v<%= version %>/\' index.html',
-        'git add index.html',
-        'git commit -m "Add assets for <%= version %>."',
-        'git push',
-        'git checkout -',
-        'rm -rf typeahead.js'
-      ].join(' && ')
-    },
-
-    clean: {
-      dist: 'dist'
-    },
-
-    connect: {
-      server: {
-        options: { port: 8888, keepalive: true }
-      }
-    },
-
-    concurrent: {
-      options: { logConcurrentOutput: true },
-      dev: ['server', 'watch']
-    },
-
-    step: {
-      options: {
-        option: false
-      }
-    }
-  });
-
-  grunt.registerTask('release', '#shipit', function(version) {
-    var curVersion = grunt.config.get('version');
-
-    version = semver.inc(curVersion, version) || version;
-
-    if (!semver.valid(version) || semver.lte(version, curVersion)) {
-      grunt.fatal('hey dummy, that version is no good!');
-    }
-
-    grunt.config.set('version', version);
-
-    grunt.task.run([
-      'exec:git_on_master',
-      'exec:git_is_clean',
-      f('step:Update to version %s?', version),
-      f('manifests:%s', version),
-      'build',
-      'exec:git_add',
-      f('exec:git_commit:%s', version),
-      f('exec:git_tag:%s', version),
-      'step:Push changes?',
-      'exec:git_push',
-      'step:Publish to npm?',
-      'exec:npm_publish',
-      'step:Publish assets?',
-      'exec:publish_assets'
-    ]);
-  });
-
-  grunt.registerTask('manifests', 'Update manifests.', function(version) {
-    var _ = grunt.util._,
-        pkg = grunt.file.readJSON('package.json'),
-        bower = grunt.file.readJSON('bower.json'),
-        jqueryPlugin = grunt.file.readJSON('typeahead.js.jquery.json');
-
-    bower = JSON.stringify(_.extend(bower, {
-      name: pkg.name,
-      version: version
-    }), null, 2);
-
-    jqueryPlugin = JSON.stringify(_.extend(jqueryPlugin, {
-      name: pkg.name,
-      title: pkg.name,
-      version: version,
-      author: pkg.author,
-      description: pkg.description,
-      keywords: pkg.keywords,
-      homepage: pkg.homepage,
-      bugs: pkg.bugs,
-      maintainers: pkg.contributors
-    }), null, 2);
-
-    pkg = JSON.stringify(_.extend(pkg, {
-      version: version
-    }), null, 2);
-
-    grunt.file.write('package.json', pkg);
-    grunt.file.write('bower.json', bower);
-    grunt.file.write('typeahead.js.jquery.json', jqueryPlugin);
-  });
-
-  // aliases
-  // -------
-
-  grunt.registerTask('default', 'build');
-  grunt.registerTask('server', 'connect:server');
-  grunt.registerTask('lint', 'jshint');
-  grunt.registerTask('dev', ['build', 'concurrent:dev']);
-  grunt.registerTask('build', [
-    'uglify:concatBloodhound',
-    'uglify:concatTypeahead',
-    'umd:bloodhound',
-    'umd:typeahead',
-    'uglify:bloodhound',
-    'uglify:bloodhoundMin',
-    'uglify:typeahead',
-    'uglify:typeaheadMin',
-    'uglify:bundle',
-    'uglify:bundleMin',
-    'sed:version'
-  ]);
-
-  // load tasks
-  // ----------
-
-  grunt.loadNpmTasks('grunt-umd');
-  grunt.loadNpmTasks('grunt-sed');
-  grunt.loadNpmTasks('grunt-exec');
-  grunt.loadNpmTasks('grunt-step');
-  grunt.loadNpmTasks('grunt-concurrent');
-  grunt.loadNpmTasks('grunt-contrib-watch');
-  grunt.loadNpmTasks('grunt-contrib-clean');
-  grunt.loadNpmTasks('grunt-contrib-uglify');
-  grunt.loadNpmTasks('grunt-contrib-jshint');
-  grunt.loadNpmTasks('grunt-contrib-concat');
-  grunt.loadNpmTasks('grunt-contrib-connect');
-};

+ 0 - 188
vendor/bower-asset/typeahead.js/README.md

@@ -1,188 +0,0 @@
-[![build status](https://secure.travis-ci.org/twitter/typeahead.js.svg?branch=master)](http://travis-ci.org/twitter/typeahead.js)
-[![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
-
-
-[typeahead.js][gh-page]
-=======================
-
-Inspired by [twitter.com]'s autocomplete search functionality, typeahead.js is 
-a flexible JavaScript library that provides a strong foundation for building 
-robust typeaheads.
-
-The typeahead.js library consists of 2 components: the suggestion engine, 
-[Bloodhound], and the UI view, [Typeahead]. 
-The suggestion engine is responsible for computing suggestions for a given 
-query. The UI view is responsible for rendering suggestions and handling DOM 
-interactions. Both components can be used separately, but when used together, 
-they can provide a rich typeahead experience.
-
-<!-- section links -->
-
-[gh-page]: http://twitter.github.io/typeahead.js/
-[twitter.com]: https://twitter.com
-[Bloodhound]: https://github.com/twitter/typeahead.js/blob/master/doc/bloodhound.md
-[Typeahead]: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md
-
-Getting Started
----------------
-
-How you acquire typeahead.js is up to you.
-
-Preferred method:
-* Install with [Bower]: `$ bower install typeahead.js`
-
-Other methods:
-* [Download zipball of latest release][zipball].
-* Download the latest dist files individually:
-  * *[bloodhound.js]* (standalone suggestion engine)
-  * *[typeahead.jquery.js]* (standalone UI view)
-  * *[typeahead.bundle.js]* (*bloodhound.js* + *typeahead.jquery.js*)
-  * *[typeahead.bundle.min.js]*
-
-**Note:** both *bloodhound.js* and *typeahead.jquery.js* have a dependency on 
-[jQuery] 1.9+.
-
-<!-- section links -->
-
-[Bower]: http://bower.io/
-[zipball]: http://twitter.github.com/typeahead.js/releases/latest/typeahead.js.zip
-[bloodhound.js]: http://twitter.github.com/typeahead.js/releases/latest/bloodhound.js
-[typeahead.jquery.js]: http://twitter.github.com/typeahead.js/releases/latest/typeahead.jquery.js
-[typeahead.bundle.js]: http://twitter.github.com/typeahead.js/releases/latest/typeahead.bundle.js
-[typeahead.bundle.min.js]: http://twitter.github.com/typeahead.js/releases/latest/typeahead.bundle.min.js
-[jQuery]: http://jquery.com/
-
-Documentation 
--------------
-
-* [Typeahead Docs]
-* [Bloodhound Docs]
-
-[Typeahead Docs]: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md
-[Bloodhound Docs]: https://github.com/twitter/typeahead.js/blob/master/doc/bloodhound.md
-
-Examples
---------
-
-For some working examples of typeahead.js, visit the [examples page].
-
-<!-- section links -->
-
-[examples page]: http://twitter.github.io/typeahead.js/examples
-
-Browser Support
----------------
-
-* Chrome
-* Firefox 3.5+
-* Safari 4+
-* Internet Explorer 8+
-* Opera 11+
-
-**NOTE:** typeahead.js is not tested on mobile browsers.
-
-Customer Support
-----------------
-
-For general questions about typeahead.js, tweet at [@typeahead].
-
-For technical questions, you should post a question on [Stack Overflow] and tag 
-it with [typeahead.js][so tag].
-
-<!-- section links -->
-
-[Stack Overflow]: http://stackoverflow.com/
-[@typeahead]: https://twitter.com/typeahead
-[so tag]: http://stackoverflow.com/questions/tagged/typeahead.js
-
-Issues
-------
-
-Discovered a bug? Please create an issue here on GitHub!
-
-https://github.com/twitter/typeahead.js/issues
-
-Versioning
-----------
-
-For transparency and insight into our release cycle, releases will be numbered 
-with the following format:
-
-`<major>.<minor>.<patch>`
-
-And constructed with the following guidelines:
-
-* Breaking backwards compatibility bumps the major
-* New additions without breaking backwards compatibility bumps the minor
-* Bug fixes and misc changes bump the patch
-
-For more information on semantic versioning, please visit http://semver.org/.
-
-Testing
--------
-
-Tests are written using [Jasmine] and ran with [Karma]. To run
-the test suite with PhantomJS, run `$ npm test`.
-
-<!-- section links -->
-
-[Jasmine]: http://jasmine.github.io/
-[Karma]: http://karma-runner.github.io/
-
-Developers
-----------
-
-If you plan on contributing to typeahead.js, be sure to read the 
-[contributing guidelines]. A good starting place for new contributors are issues
-labeled with [entry-level]. Entry-level issues tend to require minor changes 
-and provide developers a chance to get more familiar with typeahead.js before
-taking on more challenging work.
-
-In order to build and test typeahead.js, you'll need to install its dev 
-dependencies (`$ npm install`) and have [grunt-cli] 
-installed (`$ npm install -g grunt-cli`). Below is an overview of the available 
-Grunt tasks that'll be useful in development.
-
-* `grunt build` – Builds *typeahead.js* from source.
-* `grunt lint` – Runs source and test files through JSHint.
-* `grunt watch` – Rebuilds *typeahead.js* whenever a source file is modified.
-* `grunt server` – Serves files from the root of typeahead.js on localhost:8888. 
-  Useful for using *test/playground.html* for debugging/testing.
-* `grunt dev` – Runs `grunt watch` and `grunt server` in parallel.
-
-<!-- section links -->
-
-[contributing guidelines]: https://github.com/twitter/typeahead.js/blob/master/CONTRIBUTING.md
-[entry-level]: https://github.com/twitter/typeahead.js/issues?&labels=entry-level&state=open
-[grunt-cli]: https://github.com/gruntjs/grunt-cli
-
-Maintainers
------------
-
-* **Jake Harding** 
-  * [@JakeHarding](https://twitter.com/JakeHarding) 
-  * [GitHub](https://github.com/jharding)
-
-* **You?**
-
-Authors
--------
-
-* **Jake Harding** 
-  * [@JakeHarding](https://twitter.com/JakeHarding) 
-  * [GitHub](https://github.com/jharding)
-
-* **Veljko Skarich**
-  * [@vskarich](https://twitter.com/vskarich) 
-  * [GitHub](https://github.com/vskarich)
-
-* **Tim Trueman**
-  * [@timtrueman](https://twitter.com/timtrueman) 
-  * [GitHub](https://github.com/timtrueman)
-
-License
--------
-
-Copyright 2013 Twitter, Inc.
-
-Licensed under the MIT License

+ 0 - 13
vendor/bower-asset/typeahead.js/bower.json

@@ -1,13 +0,0 @@
-{
-  "name": "typeahead.js",
-  "version": "0.11.1",
-  "main": "dist/typeahead.bundle.js",
-  "dependencies": {
-    "jquery": ">=1.7"
-  },
-  "devDependencies": {
-    "jquery": "~1.7",
-    "jasmine-ajax": "~1.3.1",
-    "jasmine-jquery": "~1.5.2"
-  }
-}

+ 0 - 17
vendor/bower-asset/typeahead.js/composer.json

@@ -1,17 +0,0 @@
-{
-    "name": "twitter/typeahead.js",
-    "description": "fast and fully-featured autocomplete library",
-    "keywords": ["typeahead", "autocomplete"],
-    "homepage": "http://twitter.github.com/typeahead.js",
-    "authors": [
-        {
-            "name": "Twitter Inc.",
-            "homepage": "https://twitter.com/twitteross"
-        }
-    ],
-    "support": {
-        "issues": "https://github.com/twitter/typeahead.js/issues"
-    },
-    "author": "Twitter Inc.",
-    "license": "MIT"
-}

+ 0 - 918
vendor/bower-asset/typeahead.js/dist/bloodhound.js

@@ -1,918 +0,0 @@
-/*!
- * typeahead.js 0.11.1
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-(function(root, factory) {
-    if (typeof define === "function" && define.amd) {
-        define("bloodhound", [ "jquery" ], function(a0) {
-            return root["Bloodhound"] = factory(a0);
-        });
-    } else if (typeof exports === "object") {
-        module.exports = factory(require("jquery"));
-    } else {
-        root["Bloodhound"] = factory(jQuery);
-    }
-})(this, function($) {
-    var _ = function() {
-        "use strict";
-        return {
-            isMsie: function() {
-                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
-            },
-            isBlankString: function(str) {
-                return !str || /^\s*$/.test(str);
-            },
-            escapeRegExChars: function(str) {
-                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-            },
-            isString: function(obj) {
-                return typeof obj === "string";
-            },
-            isNumber: function(obj) {
-                return typeof obj === "number";
-            },
-            isArray: $.isArray,
-            isFunction: $.isFunction,
-            isObject: $.isPlainObject,
-            isUndefined: function(obj) {
-                return typeof obj === "undefined";
-            },
-            isElement: function(obj) {
-                return !!(obj && obj.nodeType === 1);
-            },
-            isJQuery: function(obj) {
-                return obj instanceof $;
-            },
-            toStr: function toStr(s) {
-                return _.isUndefined(s) || s === null ? "" : s + "";
-            },
-            bind: $.proxy,
-            each: function(collection, cb) {
-                $.each(collection, reverseArgs);
-                function reverseArgs(index, value) {
-                    return cb(value, index);
-                }
-            },
-            map: $.map,
-            filter: $.grep,
-            every: function(obj, test) {
-                var result = true;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (!(result = test.call(null, val, key, obj))) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            some: function(obj, test) {
-                var result = false;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (result = test.call(null, val, key, obj)) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            mixin: $.extend,
-            identity: function(x) {
-                return x;
-            },
-            clone: function(obj) {
-                return $.extend(true, {}, obj);
-            },
-            getIdGenerator: function() {
-                var counter = 0;
-                return function() {
-                    return counter++;
-                };
-            },
-            templatify: function templatify(obj) {
-                return $.isFunction(obj) ? obj : template;
-                function template() {
-                    return String(obj);
-                }
-            },
-            defer: function(fn) {
-                setTimeout(fn, 0);
-            },
-            debounce: function(func, wait, immediate) {
-                var timeout, result;
-                return function() {
-                    var context = this, args = arguments, later, callNow;
-                    later = function() {
-                        timeout = null;
-                        if (!immediate) {
-                            result = func.apply(context, args);
-                        }
-                    };
-                    callNow = immediate && !timeout;
-                    clearTimeout(timeout);
-                    timeout = setTimeout(later, wait);
-                    if (callNow) {
-                        result = func.apply(context, args);
-                    }
-                    return result;
-                };
-            },
-            throttle: function(func, wait) {
-                var context, args, timeout, result, previous, later;
-                previous = 0;
-                later = function() {
-                    previous = new Date();
-                    timeout = null;
-                    result = func.apply(context, args);
-                };
-                return function() {
-                    var now = new Date(), remaining = wait - (now - previous);
-                    context = this;
-                    args = arguments;
-                    if (remaining <= 0) {
-                        clearTimeout(timeout);
-                        timeout = null;
-                        previous = now;
-                        result = func.apply(context, args);
-                    } else if (!timeout) {
-                        timeout = setTimeout(later, remaining);
-                    }
-                    return result;
-                };
-            },
-            stringify: function(val) {
-                return _.isString(val) ? val : JSON.stringify(val);
-            },
-            noop: function() {}
-        };
-    }();
-    var VERSION = "0.11.1";
-    var tokenizers = function() {
-        "use strict";
-        return {
-            nonword: nonword,
-            whitespace: whitespace,
-            obj: {
-                nonword: getObjTokenizer(nonword),
-                whitespace: getObjTokenizer(whitespace)
-            }
-        };
-        function whitespace(str) {
-            str = _.toStr(str);
-            return str ? str.split(/\s+/) : [];
-        }
-        function nonword(str) {
-            str = _.toStr(str);
-            return str ? str.split(/\W+/) : [];
-        }
-        function getObjTokenizer(tokenizer) {
-            return function setKey(keys) {
-                keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
-                return function tokenize(o) {
-                    var tokens = [];
-                    _.each(keys, function(k) {
-                        tokens = tokens.concat(tokenizer(_.toStr(o[k])));
-                    });
-                    return tokens;
-                };
-            };
-        }
-    }();
-    var LruCache = function() {
-        "use strict";
-        function LruCache(maxSize) {
-            this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
-            this.reset();
-            if (this.maxSize <= 0) {
-                this.set = this.get = $.noop;
-            }
-        }
-        _.mixin(LruCache.prototype, {
-            set: function set(key, val) {
-                var tailItem = this.list.tail, node;
-                if (this.size >= this.maxSize) {
-                    this.list.remove(tailItem);
-                    delete this.hash[tailItem.key];
-                    this.size--;
-                }
-                if (node = this.hash[key]) {
-                    node.val = val;
-                    this.list.moveToFront(node);
-                } else {
-                    node = new Node(key, val);
-                    this.list.add(node);
-                    this.hash[key] = node;
-                    this.size++;
-                }
-            },
-            get: function get(key) {
-                var node = this.hash[key];
-                if (node) {
-                    this.list.moveToFront(node);
-                    return node.val;
-                }
-            },
-            reset: function reset() {
-                this.size = 0;
-                this.hash = {};
-                this.list = new List();
-            }
-        });
-        function List() {
-            this.head = this.tail = null;
-        }
-        _.mixin(List.prototype, {
-            add: function add(node) {
-                if (this.head) {
-                    node.next = this.head;
-                    this.head.prev = node;
-                }
-                this.head = node;
-                this.tail = this.tail || node;
-            },
-            remove: function remove(node) {
-                node.prev ? node.prev.next = node.next : this.head = node.next;
-                node.next ? node.next.prev = node.prev : this.tail = node.prev;
-            },
-            moveToFront: function(node) {
-                this.remove(node);
-                this.add(node);
-            }
-        });
-        function Node(key, val) {
-            this.key = key;
-            this.val = val;
-            this.prev = this.next = null;
-        }
-        return LruCache;
-    }();
-    var PersistentStorage = function() {
-        "use strict";
-        var LOCAL_STORAGE;
-        try {
-            LOCAL_STORAGE = window.localStorage;
-            LOCAL_STORAGE.setItem("~~~", "!");
-            LOCAL_STORAGE.removeItem("~~~");
-        } catch (err) {
-            LOCAL_STORAGE = null;
-        }
-        function PersistentStorage(namespace, override) {
-            this.prefix = [ "__", namespace, "__" ].join("");
-            this.ttlKey = "__ttl__";
-            this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
-            this.ls = override || LOCAL_STORAGE;
-            !this.ls && this._noop();
-        }
-        _.mixin(PersistentStorage.prototype, {
-            _prefix: function(key) {
-                return this.prefix + key;
-            },
-            _ttlKey: function(key) {
-                return this._prefix(key) + this.ttlKey;
-            },
-            _noop: function() {
-                this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
-            },
-            _safeSet: function(key, val) {
-                try {
-                    this.ls.setItem(key, val);
-                } catch (err) {
-                    if (err.name === "QuotaExceededError") {
-                        this.clear();
-                        this._noop();
-                    }
-                }
-            },
-            get: function(key) {
-                if (this.isExpired(key)) {
-                    this.remove(key);
-                }
-                return decode(this.ls.getItem(this._prefix(key)));
-            },
-            set: function(key, val, ttl) {
-                if (_.isNumber(ttl)) {
-                    this._safeSet(this._ttlKey(key), encode(now() + ttl));
-                } else {
-                    this.ls.removeItem(this._ttlKey(key));
-                }
-                return this._safeSet(this._prefix(key), encode(val));
-            },
-            remove: function(key) {
-                this.ls.removeItem(this._ttlKey(key));
-                this.ls.removeItem(this._prefix(key));
-                return this;
-            },
-            clear: function() {
-                var i, keys = gatherMatchingKeys(this.keyMatcher);
-                for (i = keys.length; i--; ) {
-                    this.remove(keys[i]);
-                }
-                return this;
-            },
-            isExpired: function(key) {
-                var ttl = decode(this.ls.getItem(this._ttlKey(key)));
-                return _.isNumber(ttl) && now() > ttl ? true : false;
-            }
-        });
-        return PersistentStorage;
-        function now() {
-            return new Date().getTime();
-        }
-        function encode(val) {
-            return JSON.stringify(_.isUndefined(val) ? null : val);
-        }
-        function decode(val) {
-            return $.parseJSON(val);
-        }
-        function gatherMatchingKeys(keyMatcher) {
-            var i, key, keys = [], len = LOCAL_STORAGE.length;
-            for (i = 0; i < len; i++) {
-                if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
-                    keys.push(key.replace(keyMatcher, ""));
-                }
-            }
-            return keys;
-        }
-    }();
-    var Transport = function() {
-        "use strict";
-        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
-        function Transport(o) {
-            o = o || {};
-            this.cancelled = false;
-            this.lastReq = null;
-            this._send = o.transport;
-            this._get = o.limiter ? o.limiter(this._get) : this._get;
-            this._cache = o.cache === false ? new LruCache(0) : sharedCache;
-        }
-        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
-            maxPendingRequests = num;
-        };
-        Transport.resetCache = function resetCache() {
-            sharedCache.reset();
-        };
-        _.mixin(Transport.prototype, {
-            _fingerprint: function fingerprint(o) {
-                o = o || {};
-                return o.url + o.type + $.param(o.data || {});
-            },
-            _get: function(o, cb) {
-                var that = this, fingerprint, jqXhr;
-                fingerprint = this._fingerprint(o);
-                if (this.cancelled || fingerprint !== this.lastReq) {
-                    return;
-                }
-                if (jqXhr = pendingRequests[fingerprint]) {
-                    jqXhr.done(done).fail(fail);
-                } else if (pendingRequestsCount < maxPendingRequests) {
-                    pendingRequestsCount++;
-                    pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
-                } else {
-                    this.onDeckRequestArgs = [].slice.call(arguments, 0);
-                }
-                function done(resp) {
-                    cb(null, resp);
-                    that._cache.set(fingerprint, resp);
-                }
-                function fail() {
-                    cb(true);
-                }
-                function always() {
-                    pendingRequestsCount--;
-                    delete pendingRequests[fingerprint];
-                    if (that.onDeckRequestArgs) {
-                        that._get.apply(that, that.onDeckRequestArgs);
-                        that.onDeckRequestArgs = null;
-                    }
-                }
-            },
-            get: function(o, cb) {
-                var resp, fingerprint;
-                cb = cb || $.noop;
-                o = _.isString(o) ? {
-                    url: o
-                } : o || {};
-                fingerprint = this._fingerprint(o);
-                this.cancelled = false;
-                this.lastReq = fingerprint;
-                if (resp = this._cache.get(fingerprint)) {
-                    cb(null, resp);
-                } else {
-                    this._get(o, cb);
-                }
-            },
-            cancel: function() {
-                this.cancelled = true;
-            }
-        });
-        return Transport;
-    }();
-    var SearchIndex = window.SearchIndex = function() {
-        "use strict";
-        var CHILDREN = "c", IDS = "i";
-        function SearchIndex(o) {
-            o = o || {};
-            if (!o.datumTokenizer || !o.queryTokenizer) {
-                $.error("datumTokenizer and queryTokenizer are both required");
-            }
-            this.identify = o.identify || _.stringify;
-            this.datumTokenizer = o.datumTokenizer;
-            this.queryTokenizer = o.queryTokenizer;
-            this.reset();
-        }
-        _.mixin(SearchIndex.prototype, {
-            bootstrap: function bootstrap(o) {
-                this.datums = o.datums;
-                this.trie = o.trie;
-            },
-            add: function(data) {
-                var that = this;
-                data = _.isArray(data) ? data : [ data ];
-                _.each(data, function(datum) {
-                    var id, tokens;
-                    that.datums[id = that.identify(datum)] = datum;
-                    tokens = normalizeTokens(that.datumTokenizer(datum));
-                    _.each(tokens, function(token) {
-                        var node, chars, ch;
-                        node = that.trie;
-                        chars = token.split("");
-                        while (ch = chars.shift()) {
-                            node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
-                            node[IDS].push(id);
-                        }
-                    });
-                });
-            },
-            get: function get(ids) {
-                var that = this;
-                return _.map(ids, function(id) {
-                    return that.datums[id];
-                });
-            },
-            search: function search(query) {
-                var that = this, tokens, matches;
-                tokens = normalizeTokens(this.queryTokenizer(query));
-                _.each(tokens, function(token) {
-                    var node, chars, ch, ids;
-                    if (matches && matches.length === 0) {
-                        return false;
-                    }
-                    node = that.trie;
-                    chars = token.split("");
-                    while (node && (ch = chars.shift())) {
-                        node = node[CHILDREN][ch];
-                    }
-                    if (node && chars.length === 0) {
-                        ids = node[IDS].slice(0);
-                        matches = matches ? getIntersection(matches, ids) : ids;
-                    } else {
-                        matches = [];
-                        return false;
-                    }
-                });
-                return matches ? _.map(unique(matches), function(id) {
-                    return that.datums[id];
-                }) : [];
-            },
-            all: function all() {
-                var values = [];
-                for (var key in this.datums) {
-                    values.push(this.datums[key]);
-                }
-                return values;
-            },
-            reset: function reset() {
-                this.datums = {};
-                this.trie = newNode();
-            },
-            serialize: function serialize() {
-                return {
-                    datums: this.datums,
-                    trie: this.trie
-                };
-            }
-        });
-        return SearchIndex;
-        function normalizeTokens(tokens) {
-            tokens = _.filter(tokens, function(token) {
-                return !!token;
-            });
-            tokens = _.map(tokens, function(token) {
-                return token.toLowerCase();
-            });
-            return tokens;
-        }
-        function newNode() {
-            var node = {};
-            node[IDS] = [];
-            node[CHILDREN] = {};
-            return node;
-        }
-        function unique(array) {
-            var seen = {}, uniques = [];
-            for (var i = 0, len = array.length; i < len; i++) {
-                if (!seen[array[i]]) {
-                    seen[array[i]] = true;
-                    uniques.push(array[i]);
-                }
-            }
-            return uniques;
-        }
-        function getIntersection(arrayA, arrayB) {
-            var ai = 0, bi = 0, intersection = [];
-            arrayA = arrayA.sort();
-            arrayB = arrayB.sort();
-            var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
-            while (ai < lenArrayA && bi < lenArrayB) {
-                if (arrayA[ai] < arrayB[bi]) {
-                    ai++;
-                } else if (arrayA[ai] > arrayB[bi]) {
-                    bi++;
-                } else {
-                    intersection.push(arrayA[ai]);
-                    ai++;
-                    bi++;
-                }
-            }
-            return intersection;
-        }
-    }();
-    var Prefetch = function() {
-        "use strict";
-        var keys;
-        keys = {
-            data: "data",
-            protocol: "protocol",
-            thumbprint: "thumbprint"
-        };
-        function Prefetch(o) {
-            this.url = o.url;
-            this.ttl = o.ttl;
-            this.cache = o.cache;
-            this.prepare = o.prepare;
-            this.transform = o.transform;
-            this.transport = o.transport;
-            this.thumbprint = o.thumbprint;
-            this.storage = new PersistentStorage(o.cacheKey);
-        }
-        _.mixin(Prefetch.prototype, {
-            _settings: function settings() {
-                return {
-                    url: this.url,
-                    type: "GET",
-                    dataType: "json"
-                };
-            },
-            store: function store(data) {
-                if (!this.cache) {
-                    return;
-                }
-                this.storage.set(keys.data, data, this.ttl);
-                this.storage.set(keys.protocol, location.protocol, this.ttl);
-                this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
-            },
-            fromCache: function fromCache() {
-                var stored = {}, isExpired;
-                if (!this.cache) {
-                    return null;
-                }
-                stored.data = this.storage.get(keys.data);
-                stored.protocol = this.storage.get(keys.protocol);
-                stored.thumbprint = this.storage.get(keys.thumbprint);
-                isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
-                return stored.data && !isExpired ? stored.data : null;
-            },
-            fromNetwork: function(cb) {
-                var that = this, settings;
-                if (!cb) {
-                    return;
-                }
-                settings = this.prepare(this._settings());
-                this.transport(settings).fail(onError).done(onResponse);
-                function onError() {
-                    cb(true);
-                }
-                function onResponse(resp) {
-                    cb(null, that.transform(resp));
-                }
-            },
-            clear: function clear() {
-                this.storage.clear();
-                return this;
-            }
-        });
-        return Prefetch;
-    }();
-    var Remote = function() {
-        "use strict";
-        function Remote(o) {
-            this.url = o.url;
-            this.prepare = o.prepare;
-            this.transform = o.transform;
-            this.transport = new Transport({
-                cache: o.cache,
-                limiter: o.limiter,
-                transport: o.transport
-            });
-        }
-        _.mixin(Remote.prototype, {
-            _settings: function settings() {
-                return {
-                    url: this.url,
-                    type: "GET",
-                    dataType: "json"
-                };
-            },
-            get: function get(query, cb) {
-                var that = this, settings;
-                if (!cb) {
-                    return;
-                }
-                query = query || "";
-                settings = this.prepare(query, this._settings());
-                return this.transport.get(settings, onResponse);
-                function onResponse(err, resp) {
-                    err ? cb([]) : cb(that.transform(resp));
-                }
-            },
-            cancelLastRequest: function cancelLastRequest() {
-                this.transport.cancel();
-            }
-        });
-        return Remote;
-    }();
-    var oParser = function() {
-        "use strict";
-        return function parse(o) {
-            var defaults, sorter;
-            defaults = {
-                initialize: true,
-                identify: _.stringify,
-                datumTokenizer: null,
-                queryTokenizer: null,
-                sufficient: 5,
-                sorter: null,
-                local: [],
-                prefetch: null,
-                remote: null
-            };
-            o = _.mixin(defaults, o || {});
-            !o.datumTokenizer && $.error("datumTokenizer is required");
-            !o.queryTokenizer && $.error("queryTokenizer is required");
-            sorter = o.sorter;
-            o.sorter = sorter ? function(x) {
-                return x.sort(sorter);
-            } : _.identity;
-            o.local = _.isFunction(o.local) ? o.local() : o.local;
-            o.prefetch = parsePrefetch(o.prefetch);
-            o.remote = parseRemote(o.remote);
-            return o;
-        };
-        function parsePrefetch(o) {
-            var defaults;
-            if (!o) {
-                return null;
-            }
-            defaults = {
-                url: null,
-                ttl: 24 * 60 * 60 * 1e3,
-                cache: true,
-                cacheKey: null,
-                thumbprint: "",
-                prepare: _.identity,
-                transform: _.identity,
-                transport: null
-            };
-            o = _.isString(o) ? {
-                url: o
-            } : o;
-            o = _.mixin(defaults, o);
-            !o.url && $.error("prefetch requires url to be set");
-            o.transform = o.filter || o.transform;
-            o.cacheKey = o.cacheKey || o.url;
-            o.thumbprint = VERSION + o.thumbprint;
-            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-            return o;
-        }
-        function parseRemote(o) {
-            var defaults;
-            if (!o) {
-                return;
-            }
-            defaults = {
-                url: null,
-                cache: true,
-                prepare: null,
-                replace: null,
-                wildcard: null,
-                limiter: null,
-                rateLimitBy: "debounce",
-                rateLimitWait: 300,
-                transform: _.identity,
-                transport: null
-            };
-            o = _.isString(o) ? {
-                url: o
-            } : o;
-            o = _.mixin(defaults, o);
-            !o.url && $.error("remote requires url to be set");
-            o.transform = o.filter || o.transform;
-            o.prepare = toRemotePrepare(o);
-            o.limiter = toLimiter(o);
-            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-            delete o.replace;
-            delete o.wildcard;
-            delete o.rateLimitBy;
-            delete o.rateLimitWait;
-            return o;
-        }
-        function toRemotePrepare(o) {
-            var prepare, replace, wildcard;
-            prepare = o.prepare;
-            replace = o.replace;
-            wildcard = o.wildcard;
-            if (prepare) {
-                return prepare;
-            }
-            if (replace) {
-                prepare = prepareByReplace;
-            } else if (o.wildcard) {
-                prepare = prepareByWildcard;
-            } else {
-                prepare = idenityPrepare;
-            }
-            return prepare;
-            function prepareByReplace(query, settings) {
-                settings.url = replace(settings.url, query);
-                return settings;
-            }
-            function prepareByWildcard(query, settings) {
-                settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
-                return settings;
-            }
-            function idenityPrepare(query, settings) {
-                return settings;
-            }
-        }
-        function toLimiter(o) {
-            var limiter, method, wait;
-            limiter = o.limiter;
-            method = o.rateLimitBy;
-            wait = o.rateLimitWait;
-            if (!limiter) {
-                limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
-            }
-            return limiter;
-            function debounce(wait) {
-                return function debounce(fn) {
-                    return _.debounce(fn, wait);
-                };
-            }
-            function throttle(wait) {
-                return function throttle(fn) {
-                    return _.throttle(fn, wait);
-                };
-            }
-        }
-        function callbackToDeferred(fn) {
-            return function wrapper(o) {
-                var deferred = $.Deferred();
-                fn(o, onSuccess, onError);
-                return deferred;
-                function onSuccess(resp) {
-                    _.defer(function() {
-                        deferred.resolve(resp);
-                    });
-                }
-                function onError(err) {
-                    _.defer(function() {
-                        deferred.reject(err);
-                    });
-                }
-            };
-        }
-    }();
-    var Bloodhound = function() {
-        "use strict";
-        var old;
-        old = window && window.Bloodhound;
-        function Bloodhound(o) {
-            o = oParser(o);
-            this.sorter = o.sorter;
-            this.identify = o.identify;
-            this.sufficient = o.sufficient;
-            this.local = o.local;
-            this.remote = o.remote ? new Remote(o.remote) : null;
-            this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
-            this.index = new SearchIndex({
-                identify: this.identify,
-                datumTokenizer: o.datumTokenizer,
-                queryTokenizer: o.queryTokenizer
-            });
-            o.initialize !== false && this.initialize();
-        }
-        Bloodhound.noConflict = function noConflict() {
-            window && (window.Bloodhound = old);
-            return Bloodhound;
-        };
-        Bloodhound.tokenizers = tokenizers;
-        _.mixin(Bloodhound.prototype, {
-            __ttAdapter: function ttAdapter() {
-                var that = this;
-                return this.remote ? withAsync : withoutAsync;
-                function withAsync(query, sync, async) {
-                    return that.search(query, sync, async);
-                }
-                function withoutAsync(query, sync) {
-                    return that.search(query, sync);
-                }
-            },
-            _loadPrefetch: function loadPrefetch() {
-                var that = this, deferred, serialized;
-                deferred = $.Deferred();
-                if (!this.prefetch) {
-                    deferred.resolve();
-                } else if (serialized = this.prefetch.fromCache()) {
-                    this.index.bootstrap(serialized);
-                    deferred.resolve();
-                } else {
-                    this.prefetch.fromNetwork(done);
-                }
-                return deferred.promise();
-                function done(err, data) {
-                    if (err) {
-                        return deferred.reject();
-                    }
-                    that.add(data);
-                    that.prefetch.store(that.index.serialize());
-                    deferred.resolve();
-                }
-            },
-            _initialize: function initialize() {
-                var that = this, deferred;
-                this.clear();
-                (this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
-                return this.initPromise;
-                function addLocalToIndex() {
-                    that.add(that.local);
-                }
-            },
-            initialize: function initialize(force) {
-                return !this.initPromise || force ? this._initialize() : this.initPromise;
-            },
-            add: function add(data) {
-                this.index.add(data);
-                return this;
-            },
-            get: function get(ids) {
-                ids = _.isArray(ids) ? ids : [].slice.call(arguments);
-                return this.index.get(ids);
-            },
-            search: function search(query, sync, async) {
-                var that = this, local;
-                local = this.sorter(this.index.search(query));
-                sync(this.remote ? local.slice() : local);
-                if (this.remote && local.length < this.sufficient) {
-                    this.remote.get(query, processRemote);
-                } else if (this.remote) {
-                    this.remote.cancelLastRequest();
-                }
-                return this;
-                function processRemote(remote) {
-                    var nonDuplicates = [];
-                    _.each(remote, function(r) {
-                        !_.some(local, function(l) {
-                            return that.identify(r) === that.identify(l);
-                        }) && nonDuplicates.push(r);
-                    });
-                    async && async(nonDuplicates);
-                }
-            },
-            all: function all() {
-                return this.index.all();
-            },
-            clear: function clear() {
-                this.index.reset();
-                return this;
-            },
-            clearPrefetchCache: function clearPrefetchCache() {
-                this.prefetch && this.prefetch.clear();
-                return this;
-            },
-            clearRemoteCache: function clearRemoteCache() {
-                Transport.resetCache();
-                return this;
-            },
-            ttAdapter: function ttAdapter() {
-                return this.__ttAdapter();
-            }
-        });
-        return Bloodhound;
-    }();
-    return Bloodhound;
-});

Разлика између датотеке није приказан због своје велике величине
+ 0 - 6
vendor/bower-asset/typeahead.js/dist/bloodhound.min.js


+ 0 - 2451
vendor/bower-asset/typeahead.js/dist/typeahead.bundle.js

@@ -1,2451 +0,0 @@
-/*!
- * typeahead.js 0.11.1
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-(function(root, factory) {
-    if (typeof define === "function" && define.amd) {
-        define("bloodhound", [ "jquery" ], function(a0) {
-            return root["Bloodhound"] = factory(a0);
-        });
-    } else if (typeof exports === "object") {
-        module.exports = factory(require("jquery"));
-    } else {
-        root["Bloodhound"] = factory(jQuery);
-    }
-})(this, function($) {
-    var _ = function() {
-        "use strict";
-        return {
-            isMsie: function() {
-                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
-            },
-            isBlankString: function(str) {
-                return !str || /^\s*$/.test(str);
-            },
-            escapeRegExChars: function(str) {
-                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-            },
-            isString: function(obj) {
-                return typeof obj === "string";
-            },
-            isNumber: function(obj) {
-                return typeof obj === "number";
-            },
-            isArray: $.isArray,
-            isFunction: $.isFunction,
-            isObject: $.isPlainObject,
-            isUndefined: function(obj) {
-                return typeof obj === "undefined";
-            },
-            isElement: function(obj) {
-                return !!(obj && obj.nodeType === 1);
-            },
-            isJQuery: function(obj) {
-                return obj instanceof $;
-            },
-            toStr: function toStr(s) {
-                return _.isUndefined(s) || s === null ? "" : s + "";
-            },
-            bind: $.proxy,
-            each: function(collection, cb) {
-                $.each(collection, reverseArgs);
-                function reverseArgs(index, value) {
-                    return cb(value, index);
-                }
-            },
-            map: $.map,
-            filter: $.grep,
-            every: function(obj, test) {
-                var result = true;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (!(result = test.call(null, val, key, obj))) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            some: function(obj, test) {
-                var result = false;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (result = test.call(null, val, key, obj)) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            mixin: $.extend,
-            identity: function(x) {
-                return x;
-            },
-            clone: function(obj) {
-                return $.extend(true, {}, obj);
-            },
-            getIdGenerator: function() {
-                var counter = 0;
-                return function() {
-                    return counter++;
-                };
-            },
-            templatify: function templatify(obj) {
-                return $.isFunction(obj) ? obj : template;
-                function template() {
-                    return String(obj);
-                }
-            },
-            defer: function(fn) {
-                setTimeout(fn, 0);
-            },
-            debounce: function(func, wait, immediate) {
-                var timeout, result;
-                return function() {
-                    var context = this, args = arguments, later, callNow;
-                    later = function() {
-                        timeout = null;
-                        if (!immediate) {
-                            result = func.apply(context, args);
-                        }
-                    };
-                    callNow = immediate && !timeout;
-                    clearTimeout(timeout);
-                    timeout = setTimeout(later, wait);
-                    if (callNow) {
-                        result = func.apply(context, args);
-                    }
-                    return result;
-                };
-            },
-            throttle: function(func, wait) {
-                var context, args, timeout, result, previous, later;
-                previous = 0;
-                later = function() {
-                    previous = new Date();
-                    timeout = null;
-                    result = func.apply(context, args);
-                };
-                return function() {
-                    var now = new Date(), remaining = wait - (now - previous);
-                    context = this;
-                    args = arguments;
-                    if (remaining <= 0) {
-                        clearTimeout(timeout);
-                        timeout = null;
-                        previous = now;
-                        result = func.apply(context, args);
-                    } else if (!timeout) {
-                        timeout = setTimeout(later, remaining);
-                    }
-                    return result;
-                };
-            },
-            stringify: function(val) {
-                return _.isString(val) ? val : JSON.stringify(val);
-            },
-            noop: function() {}
-        };
-    }();
-    var VERSION = "0.11.1";
-    var tokenizers = function() {
-        "use strict";
-        return {
-            nonword: nonword,
-            whitespace: whitespace,
-            obj: {
-                nonword: getObjTokenizer(nonword),
-                whitespace: getObjTokenizer(whitespace)
-            }
-        };
-        function whitespace(str) {
-            str = _.toStr(str);
-            return str ? str.split(/\s+/) : [];
-        }
-        function nonword(str) {
-            str = _.toStr(str);
-            return str ? str.split(/\W+/) : [];
-        }
-        function getObjTokenizer(tokenizer) {
-            return function setKey(keys) {
-                keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
-                return function tokenize(o) {
-                    var tokens = [];
-                    _.each(keys, function(k) {
-                        tokens = tokens.concat(tokenizer(_.toStr(o[k])));
-                    });
-                    return tokens;
-                };
-            };
-        }
-    }();
-    var LruCache = function() {
-        "use strict";
-        function LruCache(maxSize) {
-            this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
-            this.reset();
-            if (this.maxSize <= 0) {
-                this.set = this.get = $.noop;
-            }
-        }
-        _.mixin(LruCache.prototype, {
-            set: function set(key, val) {
-                var tailItem = this.list.tail, node;
-                if (this.size >= this.maxSize) {
-                    this.list.remove(tailItem);
-                    delete this.hash[tailItem.key];
-                    this.size--;
-                }
-                if (node = this.hash[key]) {
-                    node.val = val;
-                    this.list.moveToFront(node);
-                } else {
-                    node = new Node(key, val);
-                    this.list.add(node);
-                    this.hash[key] = node;
-                    this.size++;
-                }
-            },
-            get: function get(key) {
-                var node = this.hash[key];
-                if (node) {
-                    this.list.moveToFront(node);
-                    return node.val;
-                }
-            },
-            reset: function reset() {
-                this.size = 0;
-                this.hash = {};
-                this.list = new List();
-            }
-        });
-        function List() {
-            this.head = this.tail = null;
-        }
-        _.mixin(List.prototype, {
-            add: function add(node) {
-                if (this.head) {
-                    node.next = this.head;
-                    this.head.prev = node;
-                }
-                this.head = node;
-                this.tail = this.tail || node;
-            },
-            remove: function remove(node) {
-                node.prev ? node.prev.next = node.next : this.head = node.next;
-                node.next ? node.next.prev = node.prev : this.tail = node.prev;
-            },
-            moveToFront: function(node) {
-                this.remove(node);
-                this.add(node);
-            }
-        });
-        function Node(key, val) {
-            this.key = key;
-            this.val = val;
-            this.prev = this.next = null;
-        }
-        return LruCache;
-    }();
-    var PersistentStorage = function() {
-        "use strict";
-        var LOCAL_STORAGE;
-        try {
-            LOCAL_STORAGE = window.localStorage;
-            LOCAL_STORAGE.setItem("~~~", "!");
-            LOCAL_STORAGE.removeItem("~~~");
-        } catch (err) {
-            LOCAL_STORAGE = null;
-        }
-        function PersistentStorage(namespace, override) {
-            this.prefix = [ "__", namespace, "__" ].join("");
-            this.ttlKey = "__ttl__";
-            this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
-            this.ls = override || LOCAL_STORAGE;
-            !this.ls && this._noop();
-        }
-        _.mixin(PersistentStorage.prototype, {
-            _prefix: function(key) {
-                return this.prefix + key;
-            },
-            _ttlKey: function(key) {
-                return this._prefix(key) + this.ttlKey;
-            },
-            _noop: function() {
-                this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
-            },
-            _safeSet: function(key, val) {
-                try {
-                    this.ls.setItem(key, val);
-                } catch (err) {
-                    if (err.name === "QuotaExceededError") {
-                        this.clear();
-                        this._noop();
-                    }
-                }
-            },
-            get: function(key) {
-                if (this.isExpired(key)) {
-                    this.remove(key);
-                }
-                return decode(this.ls.getItem(this._prefix(key)));
-            },
-            set: function(key, val, ttl) {
-                if (_.isNumber(ttl)) {
-                    this._safeSet(this._ttlKey(key), encode(now() + ttl));
-                } else {
-                    this.ls.removeItem(this._ttlKey(key));
-                }
-                return this._safeSet(this._prefix(key), encode(val));
-            },
-            remove: function(key) {
-                this.ls.removeItem(this._ttlKey(key));
-                this.ls.removeItem(this._prefix(key));
-                return this;
-            },
-            clear: function() {
-                var i, keys = gatherMatchingKeys(this.keyMatcher);
-                for (i = keys.length; i--; ) {
-                    this.remove(keys[i]);
-                }
-                return this;
-            },
-            isExpired: function(key) {
-                var ttl = decode(this.ls.getItem(this._ttlKey(key)));
-                return _.isNumber(ttl) && now() > ttl ? true : false;
-            }
-        });
-        return PersistentStorage;
-        function now() {
-            return new Date().getTime();
-        }
-        function encode(val) {
-            return JSON.stringify(_.isUndefined(val) ? null : val);
-        }
-        function decode(val) {
-            return $.parseJSON(val);
-        }
-        function gatherMatchingKeys(keyMatcher) {
-            var i, key, keys = [], len = LOCAL_STORAGE.length;
-            for (i = 0; i < len; i++) {
-                if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
-                    keys.push(key.replace(keyMatcher, ""));
-                }
-            }
-            return keys;
-        }
-    }();
-    var Transport = function() {
-        "use strict";
-        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
-        function Transport(o) {
-            o = o || {};
-            this.cancelled = false;
-            this.lastReq = null;
-            this._send = o.transport;
-            this._get = o.limiter ? o.limiter(this._get) : this._get;
-            this._cache = o.cache === false ? new LruCache(0) : sharedCache;
-        }
-        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
-            maxPendingRequests = num;
-        };
-        Transport.resetCache = function resetCache() {
-            sharedCache.reset();
-        };
-        _.mixin(Transport.prototype, {
-            _fingerprint: function fingerprint(o) {
-                o = o || {};
-                return o.url + o.type + $.param(o.data || {});
-            },
-            _get: function(o, cb) {
-                var that = this, fingerprint, jqXhr;
-                fingerprint = this._fingerprint(o);
-                if (this.cancelled || fingerprint !== this.lastReq) {
-                    return;
-                }
-                if (jqXhr = pendingRequests[fingerprint]) {
-                    jqXhr.done(done).fail(fail);
-                } else if (pendingRequestsCount < maxPendingRequests) {
-                    pendingRequestsCount++;
-                    pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
-                } else {
-                    this.onDeckRequestArgs = [].slice.call(arguments, 0);
-                }
-                function done(resp) {
-                    cb(null, resp);
-                    that._cache.set(fingerprint, resp);
-                }
-                function fail() {
-                    cb(true);
-                }
-                function always() {
-                    pendingRequestsCount--;
-                    delete pendingRequests[fingerprint];
-                    if (that.onDeckRequestArgs) {
-                        that._get.apply(that, that.onDeckRequestArgs);
-                        that.onDeckRequestArgs = null;
-                    }
-                }
-            },
-            get: function(o, cb) {
-                var resp, fingerprint;
-                cb = cb || $.noop;
-                o = _.isString(o) ? {
-                    url: o
-                } : o || {};
-                fingerprint = this._fingerprint(o);
-                this.cancelled = false;
-                this.lastReq = fingerprint;
-                if (resp = this._cache.get(fingerprint)) {
-                    cb(null, resp);
-                } else {
-                    this._get(o, cb);
-                }
-            },
-            cancel: function() {
-                this.cancelled = true;
-            }
-        });
-        return Transport;
-    }();
-    var SearchIndex = window.SearchIndex = function() {
-        "use strict";
-        var CHILDREN = "c", IDS = "i";
-        function SearchIndex(o) {
-            o = o || {};
-            if (!o.datumTokenizer || !o.queryTokenizer) {
-                $.error("datumTokenizer and queryTokenizer are both required");
-            }
-            this.identify = o.identify || _.stringify;
-            this.datumTokenizer = o.datumTokenizer;
-            this.queryTokenizer = o.queryTokenizer;
-            this.reset();
-        }
-        _.mixin(SearchIndex.prototype, {
-            bootstrap: function bootstrap(o) {
-                this.datums = o.datums;
-                this.trie = o.trie;
-            },
-            add: function(data) {
-                var that = this;
-                data = _.isArray(data) ? data : [ data ];
-                _.each(data, function(datum) {
-                    var id, tokens;
-                    that.datums[id = that.identify(datum)] = datum;
-                    tokens = normalizeTokens(that.datumTokenizer(datum));
-                    _.each(tokens, function(token) {
-                        var node, chars, ch;
-                        node = that.trie;
-                        chars = token.split("");
-                        while (ch = chars.shift()) {
-                            node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
-                            node[IDS].push(id);
-                        }
-                    });
-                });
-            },
-            get: function get(ids) {
-                var that = this;
-                return _.map(ids, function(id) {
-                    return that.datums[id];
-                });
-            },
-            search: function search(query) {
-                var that = this, tokens, matches;
-                tokens = normalizeTokens(this.queryTokenizer(query));
-                _.each(tokens, function(token) {
-                    var node, chars, ch, ids;
-                    if (matches && matches.length === 0) {
-                        return false;
-                    }
-                    node = that.trie;
-                    chars = token.split("");
-                    while (node && (ch = chars.shift())) {
-                        node = node[CHILDREN][ch];
-                    }
-                    if (node && chars.length === 0) {
-                        ids = node[IDS].slice(0);
-                        matches = matches ? getIntersection(matches, ids) : ids;
-                    } else {
-                        matches = [];
-                        return false;
-                    }
-                });
-                return matches ? _.map(unique(matches), function(id) {
-                    return that.datums[id];
-                }) : [];
-            },
-            all: function all() {
-                var values = [];
-                for (var key in this.datums) {
-                    values.push(this.datums[key]);
-                }
-                return values;
-            },
-            reset: function reset() {
-                this.datums = {};
-                this.trie = newNode();
-            },
-            serialize: function serialize() {
-                return {
-                    datums: this.datums,
-                    trie: this.trie
-                };
-            }
-        });
-        return SearchIndex;
-        function normalizeTokens(tokens) {
-            tokens = _.filter(tokens, function(token) {
-                return !!token;
-            });
-            tokens = _.map(tokens, function(token) {
-                return token.toLowerCase();
-            });
-            return tokens;
-        }
-        function newNode() {
-            var node = {};
-            node[IDS] = [];
-            node[CHILDREN] = {};
-            return node;
-        }
-        function unique(array) {
-            var seen = {}, uniques = [];
-            for (var i = 0, len = array.length; i < len; i++) {
-                if (!seen[array[i]]) {
-                    seen[array[i]] = true;
-                    uniques.push(array[i]);
-                }
-            }
-            return uniques;
-        }
-        function getIntersection(arrayA, arrayB) {
-            var ai = 0, bi = 0, intersection = [];
-            arrayA = arrayA.sort();
-            arrayB = arrayB.sort();
-            var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
-            while (ai < lenArrayA && bi < lenArrayB) {
-                if (arrayA[ai] < arrayB[bi]) {
-                    ai++;
-                } else if (arrayA[ai] > arrayB[bi]) {
-                    bi++;
-                } else {
-                    intersection.push(arrayA[ai]);
-                    ai++;
-                    bi++;
-                }
-            }
-            return intersection;
-        }
-    }();
-    var Prefetch = function() {
-        "use strict";
-        var keys;
-        keys = {
-            data: "data",
-            protocol: "protocol",
-            thumbprint: "thumbprint"
-        };
-        function Prefetch(o) {
-            this.url = o.url;
-            this.ttl = o.ttl;
-            this.cache = o.cache;
-            this.prepare = o.prepare;
-            this.transform = o.transform;
-            this.transport = o.transport;
-            this.thumbprint = o.thumbprint;
-            this.storage = new PersistentStorage(o.cacheKey);
-        }
-        _.mixin(Prefetch.prototype, {
-            _settings: function settings() {
-                return {
-                    url: this.url,
-                    type: "GET",
-                    dataType: "json"
-                };
-            },
-            store: function store(data) {
-                if (!this.cache) {
-                    return;
-                }
-                this.storage.set(keys.data, data, this.ttl);
-                this.storage.set(keys.protocol, location.protocol, this.ttl);
-                this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
-            },
-            fromCache: function fromCache() {
-                var stored = {}, isExpired;
-                if (!this.cache) {
-                    return null;
-                }
-                stored.data = this.storage.get(keys.data);
-                stored.protocol = this.storage.get(keys.protocol);
-                stored.thumbprint = this.storage.get(keys.thumbprint);
-                isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
-                return stored.data && !isExpired ? stored.data : null;
-            },
-            fromNetwork: function(cb) {
-                var that = this, settings;
-                if (!cb) {
-                    return;
-                }
-                settings = this.prepare(this._settings());
-                this.transport(settings).fail(onError).done(onResponse);
-                function onError() {
-                    cb(true);
-                }
-                function onResponse(resp) {
-                    cb(null, that.transform(resp));
-                }
-            },
-            clear: function clear() {
-                this.storage.clear();
-                return this;
-            }
-        });
-        return Prefetch;
-    }();
-    var Remote = function() {
-        "use strict";
-        function Remote(o) {
-            this.url = o.url;
-            this.prepare = o.prepare;
-            this.transform = o.transform;
-            this.transport = new Transport({
-                cache: o.cache,
-                limiter: o.limiter,
-                transport: o.transport
-            });
-        }
-        _.mixin(Remote.prototype, {
-            _settings: function settings() {
-                return {
-                    url: this.url,
-                    type: "GET",
-                    dataType: "json"
-                };
-            },
-            get: function get(query, cb) {
-                var that = this, settings;
-                if (!cb) {
-                    return;
-                }
-                query = query || "";
-                settings = this.prepare(query, this._settings());
-                return this.transport.get(settings, onResponse);
-                function onResponse(err, resp) {
-                    err ? cb([]) : cb(that.transform(resp));
-                }
-            },
-            cancelLastRequest: function cancelLastRequest() {
-                this.transport.cancel();
-            }
-        });
-        return Remote;
-    }();
-    var oParser = function() {
-        "use strict";
-        return function parse(o) {
-            var defaults, sorter;
-            defaults = {
-                initialize: true,
-                identify: _.stringify,
-                datumTokenizer: null,
-                queryTokenizer: null,
-                sufficient: 5,
-                sorter: null,
-                local: [],
-                prefetch: null,
-                remote: null
-            };
-            o = _.mixin(defaults, o || {});
-            !o.datumTokenizer && $.error("datumTokenizer is required");
-            !o.queryTokenizer && $.error("queryTokenizer is required");
-            sorter = o.sorter;
-            o.sorter = sorter ? function(x) {
-                return x.sort(sorter);
-            } : _.identity;
-            o.local = _.isFunction(o.local) ? o.local() : o.local;
-            o.prefetch = parsePrefetch(o.prefetch);
-            o.remote = parseRemote(o.remote);
-            return o;
-        };
-        function parsePrefetch(o) {
-            var defaults;
-            if (!o) {
-                return null;
-            }
-            defaults = {
-                url: null,
-                ttl: 24 * 60 * 60 * 1e3,
-                cache: true,
-                cacheKey: null,
-                thumbprint: "",
-                prepare: _.identity,
-                transform: _.identity,
-                transport: null
-            };
-            o = _.isString(o) ? {
-                url: o
-            } : o;
-            o = _.mixin(defaults, o);
-            !o.url && $.error("prefetch requires url to be set");
-            o.transform = o.filter || o.transform;
-            o.cacheKey = o.cacheKey || o.url;
-            o.thumbprint = VERSION + o.thumbprint;
-            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-            return o;
-        }
-        function parseRemote(o) {
-            var defaults;
-            if (!o) {
-                return;
-            }
-            defaults = {
-                url: null,
-                cache: true,
-                prepare: null,
-                replace: null,
-                wildcard: null,
-                limiter: null,
-                rateLimitBy: "debounce",
-                rateLimitWait: 300,
-                transform: _.identity,
-                transport: null
-            };
-            o = _.isString(o) ? {
-                url: o
-            } : o;
-            o = _.mixin(defaults, o);
-            !o.url && $.error("remote requires url to be set");
-            o.transform = o.filter || o.transform;
-            o.prepare = toRemotePrepare(o);
-            o.limiter = toLimiter(o);
-            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-            delete o.replace;
-            delete o.wildcard;
-            delete o.rateLimitBy;
-            delete o.rateLimitWait;
-            return o;
-        }
-        function toRemotePrepare(o) {
-            var prepare, replace, wildcard;
-            prepare = o.prepare;
-            replace = o.replace;
-            wildcard = o.wildcard;
-            if (prepare) {
-                return prepare;
-            }
-            if (replace) {
-                prepare = prepareByReplace;
-            } else if (o.wildcard) {
-                prepare = prepareByWildcard;
-            } else {
-                prepare = idenityPrepare;
-            }
-            return prepare;
-            function prepareByReplace(query, settings) {
-                settings.url = replace(settings.url, query);
-                return settings;
-            }
-            function prepareByWildcard(query, settings) {
-                settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
-                return settings;
-            }
-            function idenityPrepare(query, settings) {
-                return settings;
-            }
-        }
-        function toLimiter(o) {
-            var limiter, method, wait;
-            limiter = o.limiter;
-            method = o.rateLimitBy;
-            wait = o.rateLimitWait;
-            if (!limiter) {
-                limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
-            }
-            return limiter;
-            function debounce(wait) {
-                return function debounce(fn) {
-                    return _.debounce(fn, wait);
-                };
-            }
-            function throttle(wait) {
-                return function throttle(fn) {
-                    return _.throttle(fn, wait);
-                };
-            }
-        }
-        function callbackToDeferred(fn) {
-            return function wrapper(o) {
-                var deferred = $.Deferred();
-                fn(o, onSuccess, onError);
-                return deferred;
-                function onSuccess(resp) {
-                    _.defer(function() {
-                        deferred.resolve(resp);
-                    });
-                }
-                function onError(err) {
-                    _.defer(function() {
-                        deferred.reject(err);
-                    });
-                }
-            };
-        }
-    }();
-    var Bloodhound = function() {
-        "use strict";
-        var old;
-        old = window && window.Bloodhound;
-        function Bloodhound(o) {
-            o = oParser(o);
-            this.sorter = o.sorter;
-            this.identify = o.identify;
-            this.sufficient = o.sufficient;
-            this.local = o.local;
-            this.remote = o.remote ? new Remote(o.remote) : null;
-            this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
-            this.index = new SearchIndex({
-                identify: this.identify,
-                datumTokenizer: o.datumTokenizer,
-                queryTokenizer: o.queryTokenizer
-            });
-            o.initialize !== false && this.initialize();
-        }
-        Bloodhound.noConflict = function noConflict() {
-            window && (window.Bloodhound = old);
-            return Bloodhound;
-        };
-        Bloodhound.tokenizers = tokenizers;
-        _.mixin(Bloodhound.prototype, {
-            __ttAdapter: function ttAdapter() {
-                var that = this;
-                return this.remote ? withAsync : withoutAsync;
-                function withAsync(query, sync, async) {
-                    return that.search(query, sync, async);
-                }
-                function withoutAsync(query, sync) {
-                    return that.search(query, sync);
-                }
-            },
-            _loadPrefetch: function loadPrefetch() {
-                var that = this, deferred, serialized;
-                deferred = $.Deferred();
-                if (!this.prefetch) {
-                    deferred.resolve();
-                } else if (serialized = this.prefetch.fromCache()) {
-                    this.index.bootstrap(serialized);
-                    deferred.resolve();
-                } else {
-                    this.prefetch.fromNetwork(done);
-                }
-                return deferred.promise();
-                function done(err, data) {
-                    if (err) {
-                        return deferred.reject();
-                    }
-                    that.add(data);
-                    that.prefetch.store(that.index.serialize());
-                    deferred.resolve();
-                }
-            },
-            _initialize: function initialize() {
-                var that = this, deferred;
-                this.clear();
-                (this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
-                return this.initPromise;
-                function addLocalToIndex() {
-                    that.add(that.local);
-                }
-            },
-            initialize: function initialize(force) {
-                return !this.initPromise || force ? this._initialize() : this.initPromise;
-            },
-            add: function add(data) {
-                this.index.add(data);
-                return this;
-            },
-            get: function get(ids) {
-                ids = _.isArray(ids) ? ids : [].slice.call(arguments);
-                return this.index.get(ids);
-            },
-            search: function search(query, sync, async) {
-                var that = this, local;
-                local = this.sorter(this.index.search(query));
-                sync(this.remote ? local.slice() : local);
-                if (this.remote && local.length < this.sufficient) {
-                    this.remote.get(query, processRemote);
-                } else if (this.remote) {
-                    this.remote.cancelLastRequest();
-                }
-                return this;
-                function processRemote(remote) {
-                    var nonDuplicates = [];
-                    _.each(remote, function(r) {
-                        !_.some(local, function(l) {
-                            return that.identify(r) === that.identify(l);
-                        }) && nonDuplicates.push(r);
-                    });
-                    async && async(nonDuplicates);
-                }
-            },
-            all: function all() {
-                return this.index.all();
-            },
-            clear: function clear() {
-                this.index.reset();
-                return this;
-            },
-            clearPrefetchCache: function clearPrefetchCache() {
-                this.prefetch && this.prefetch.clear();
-                return this;
-            },
-            clearRemoteCache: function clearRemoteCache() {
-                Transport.resetCache();
-                return this;
-            },
-            ttAdapter: function ttAdapter() {
-                return this.__ttAdapter();
-            }
-        });
-        return Bloodhound;
-    }();
-    return Bloodhound;
-});
-
-(function(root, factory) {
-    if (typeof define === "function" && define.amd) {
-        define("typeahead.js", [ "jquery" ], function(a0) {
-            return factory(a0);
-        });
-    } else if (typeof exports === "object") {
-        module.exports = factory(require("jquery"));
-    } else {
-        factory(jQuery);
-    }
-})(this, function($) {
-    var _ = function() {
-        "use strict";
-        return {
-            isMsie: function() {
-                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
-            },
-            isBlankString: function(str) {
-                return !str || /^\s*$/.test(str);
-            },
-            escapeRegExChars: function(str) {
-                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-            },
-            isString: function(obj) {
-                return typeof obj === "string";
-            },
-            isNumber: function(obj) {
-                return typeof obj === "number";
-            },
-            isArray: $.isArray,
-            isFunction: $.isFunction,
-            isObject: $.isPlainObject,
-            isUndefined: function(obj) {
-                return typeof obj === "undefined";
-            },
-            isElement: function(obj) {
-                return !!(obj && obj.nodeType === 1);
-            },
-            isJQuery: function(obj) {
-                return obj instanceof $;
-            },
-            toStr: function toStr(s) {
-                return _.isUndefined(s) || s === null ? "" : s + "";
-            },
-            bind: $.proxy,
-            each: function(collection, cb) {
-                $.each(collection, reverseArgs);
-                function reverseArgs(index, value) {
-                    return cb(value, index);
-                }
-            },
-            map: $.map,
-            filter: $.grep,
-            every: function(obj, test) {
-                var result = true;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (!(result = test.call(null, val, key, obj))) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            some: function(obj, test) {
-                var result = false;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (result = test.call(null, val, key, obj)) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            mixin: $.extend,
-            identity: function(x) {
-                return x;
-            },
-            clone: function(obj) {
-                return $.extend(true, {}, obj);
-            },
-            getIdGenerator: function() {
-                var counter = 0;
-                return function() {
-                    return counter++;
-                };
-            },
-            templatify: function templatify(obj) {
-                return $.isFunction(obj) ? obj : template;
-                function template() {
-                    return String(obj);
-                }
-            },
-            defer: function(fn) {
-                setTimeout(fn, 0);
-            },
-            debounce: function(func, wait, immediate) {
-                var timeout, result;
-                return function() {
-                    var context = this, args = arguments, later, callNow;
-                    later = function() {
-                        timeout = null;
-                        if (!immediate) {
-                            result = func.apply(context, args);
-                        }
-                    };
-                    callNow = immediate && !timeout;
-                    clearTimeout(timeout);
-                    timeout = setTimeout(later, wait);
-                    if (callNow) {
-                        result = func.apply(context, args);
-                    }
-                    return result;
-                };
-            },
-            throttle: function(func, wait) {
-                var context, args, timeout, result, previous, later;
-                previous = 0;
-                later = function() {
-                    previous = new Date();
-                    timeout = null;
-                    result = func.apply(context, args);
-                };
-                return function() {
-                    var now = new Date(), remaining = wait - (now - previous);
-                    context = this;
-                    args = arguments;
-                    if (remaining <= 0) {
-                        clearTimeout(timeout);
-                        timeout = null;
-                        previous = now;
-                        result = func.apply(context, args);
-                    } else if (!timeout) {
-                        timeout = setTimeout(later, remaining);
-                    }
-                    return result;
-                };
-            },
-            stringify: function(val) {
-                return _.isString(val) ? val : JSON.stringify(val);
-            },
-            noop: function() {}
-        };
-    }();
-    var WWW = function() {
-        "use strict";
-        var defaultClassNames = {
-            wrapper: "twitter-typeahead",
-            input: "tt-input",
-            hint: "tt-hint",
-            menu: "tt-menu",
-            dataset: "tt-dataset",
-            suggestion: "tt-suggestion",
-            selectable: "tt-selectable",
-            empty: "tt-empty",
-            open: "tt-open",
-            cursor: "tt-cursor",
-            highlight: "tt-highlight"
-        };
-        return build;
-        function build(o) {
-            var www, classes;
-            classes = _.mixin({}, defaultClassNames, o);
-            www = {
-                css: buildCss(),
-                classes: classes,
-                html: buildHtml(classes),
-                selectors: buildSelectors(classes)
-            };
-            return {
-                css: www.css,
-                html: www.html,
-                classes: www.classes,
-                selectors: www.selectors,
-                mixin: function(o) {
-                    _.mixin(o, www);
-                }
-            };
-        }
-        function buildHtml(c) {
-            return {
-                wrapper: '<span class="' + c.wrapper + '"></span>',
-                menu: '<div class="' + c.menu + '"></div>'
-            };
-        }
-        function buildSelectors(classes) {
-            var selectors = {};
-            _.each(classes, function(v, k) {
-                selectors[k] = "." + v;
-            });
-            return selectors;
-        }
-        function buildCss() {
-            var css = {
-                wrapper: {
-                    position: "relative",
-                    display: "inline-block"
-                },
-                hint: {
-                    position: "absolute",
-                    top: "0",
-                    left: "0",
-                    borderColor: "transparent",
-                    boxShadow: "none",
-                    opacity: "1"
-                },
-                input: {
-                    position: "relative",
-                    verticalAlign: "top",
-                    backgroundColor: "transparent"
-                },
-                inputWithNoHint: {
-                    position: "relative",
-                    verticalAlign: "top"
-                },
-                menu: {
-                    position: "absolute",
-                    top: "100%",
-                    left: "0",
-                    zIndex: "100",
-                    display: "none"
-                },
-                ltr: {
-                    left: "0",
-                    right: "auto"
-                },
-                rtl: {
-                    left: "auto",
-                    right: " 0"
-                }
-            };
-            if (_.isMsie()) {
-                _.mixin(css.input, {
-                    backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
-                });
-            }
-            return css;
-        }
-    }();
-    var EventBus = function() {
-        "use strict";
-        var namespace, deprecationMap;
-        namespace = "typeahead:";
-        deprecationMap = {
-            render: "rendered",
-            cursorchange: "cursorchanged",
-            select: "selected",
-            autocomplete: "autocompleted"
-        };
-        function EventBus(o) {
-            if (!o || !o.el) {
-                $.error("EventBus initialized without el");
-            }
-            this.$el = $(o.el);
-        }
-        _.mixin(EventBus.prototype, {
-            _trigger: function(type, args) {
-                var $e;
-                $e = $.Event(namespace + type);
-                (args = args || []).unshift($e);
-                this.$el.trigger.apply(this.$el, args);
-                return $e;
-            },
-            before: function(type) {
-                var args, $e;
-                args = [].slice.call(arguments, 1);
-                $e = this._trigger("before" + type, args);
-                return $e.isDefaultPrevented();
-            },
-            trigger: function(type) {
-                var deprecatedType;
-                this._trigger(type, [].slice.call(arguments, 1));
-                if (deprecatedType = deprecationMap[type]) {
-                    this._trigger(deprecatedType, [].slice.call(arguments, 1));
-                }
-            }
-        });
-        return EventBus;
-    }();
-    var EventEmitter = function() {
-        "use strict";
-        var splitter = /\s+/, nextTick = getNextTick();
-        return {
-            onSync: onSync,
-            onAsync: onAsync,
-            off: off,
-            trigger: trigger
-        };
-        function on(method, types, cb, context) {
-            var type;
-            if (!cb) {
-                return this;
-            }
-            types = types.split(splitter);
-            cb = context ? bindContext(cb, context) : cb;
-            this._callbacks = this._callbacks || {};
-            while (type = types.shift()) {
-                this._callbacks[type] = this._callbacks[type] || {
-                    sync: [],
-                    async: []
-                };
-                this._callbacks[type][method].push(cb);
-            }
-            return this;
-        }
-        function onAsync(types, cb, context) {
-            return on.call(this, "async", types, cb, context);
-        }
-        function onSync(types, cb, context) {
-            return on.call(this, "sync", types, cb, context);
-        }
-        function off(types) {
-            var type;
-            if (!this._callbacks) {
-                return this;
-            }
-            types = types.split(splitter);
-            while (type = types.shift()) {
-                delete this._callbacks[type];
-            }
-            return this;
-        }
-        function trigger(types) {
-            var type, callbacks, args, syncFlush, asyncFlush;
-            if (!this._callbacks) {
-                return this;
-            }
-            types = types.split(splitter);
-            args = [].slice.call(arguments, 1);
-            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
-                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
-                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
-                syncFlush() && nextTick(asyncFlush);
-            }
-            return this;
-        }
-        function getFlush(callbacks, context, args) {
-            return flush;
-            function flush() {
-                var cancelled;
-                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
-                    cancelled = callbacks[i].apply(context, args) === false;
-                }
-                return !cancelled;
-            }
-        }
-        function getNextTick() {
-            var nextTickFn;
-            if (window.setImmediate) {
-                nextTickFn = function nextTickSetImmediate(fn) {
-                    setImmediate(function() {
-                        fn();
-                    });
-                };
-            } else {
-                nextTickFn = function nextTickSetTimeout(fn) {
-                    setTimeout(function() {
-                        fn();
-                    }, 0);
-                };
-            }
-            return nextTickFn;
-        }
-        function bindContext(fn, context) {
-            return fn.bind ? fn.bind(context) : function() {
-                fn.apply(context, [].slice.call(arguments, 0));
-            };
-        }
-    }();
-    var highlight = function(doc) {
-        "use strict";
-        var defaults = {
-            node: null,
-            pattern: null,
-            tagName: "strong",
-            className: null,
-            wordsOnly: false,
-            caseSensitive: false
-        };
-        return function hightlight(o) {
-            var regex;
-            o = _.mixin({}, defaults, o);
-            if (!o.node || !o.pattern) {
-                return;
-            }
-            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
-            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
-            traverse(o.node, hightlightTextNode);
-            function hightlightTextNode(textNode) {
-                var match, patternNode, wrapperNode;
-                if (match = regex.exec(textNode.data)) {
-                    wrapperNode = doc.createElement(o.tagName);
-                    o.className && (wrapperNode.className = o.className);
-                    patternNode = textNode.splitText(match.index);
-                    patternNode.splitText(match[0].length);
-                    wrapperNode.appendChild(patternNode.cloneNode(true));
-                    textNode.parentNode.replaceChild(wrapperNode, patternNode);
-                }
-                return !!match;
-            }
-            function traverse(el, hightlightTextNode) {
-                var childNode, TEXT_NODE_TYPE = 3;
-                for (var i = 0; i < el.childNodes.length; i++) {
-                    childNode = el.childNodes[i];
-                    if (childNode.nodeType === TEXT_NODE_TYPE) {
-                        i += hightlightTextNode(childNode) ? 1 : 0;
-                    } else {
-                        traverse(childNode, hightlightTextNode);
-                    }
-                }
-            }
-        };
-        function getRegex(patterns, caseSensitive, wordsOnly) {
-            var escapedPatterns = [], regexStr;
-            for (var i = 0, len = patterns.length; i < len; i++) {
-                escapedPatterns.push(_.escapeRegExChars(patterns[i]));
-            }
-            regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
-            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
-        }
-    }(window.document);
-    var Input = function() {
-        "use strict";
-        var specialKeyCodeMap;
-        specialKeyCodeMap = {
-            9: "tab",
-            27: "esc",
-            37: "left",
-            39: "right",
-            13: "enter",
-            38: "up",
-            40: "down"
-        };
-        function Input(o, www) {
-            o = o || {};
-            if (!o.input) {
-                $.error("input is missing");
-            }
-            www.mixin(this);
-            this.$hint = $(o.hint);
-            this.$input = $(o.input);
-            this.query = this.$input.val();
-            this.queryWhenFocused = this.hasFocus() ? this.query : null;
-            this.$overflowHelper = buildOverflowHelper(this.$input);
-            this._checkLanguageDirection();
-            if (this.$hint.length === 0) {
-                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
-            }
-        }
-        Input.normalizeQuery = function(str) {
-            return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
-        };
-        _.mixin(Input.prototype, EventEmitter, {
-            _onBlur: function onBlur() {
-                this.resetInputValue();
-                this.trigger("blurred");
-            },
-            _onFocus: function onFocus() {
-                this.queryWhenFocused = this.query;
-                this.trigger("focused");
-            },
-            _onKeydown: function onKeydown($e) {
-                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
-                this._managePreventDefault(keyName, $e);
-                if (keyName && this._shouldTrigger(keyName, $e)) {
-                    this.trigger(keyName + "Keyed", $e);
-                }
-            },
-            _onInput: function onInput() {
-                this._setQuery(this.getInputValue());
-                this.clearHintIfInvalid();
-                this._checkLanguageDirection();
-            },
-            _managePreventDefault: function managePreventDefault(keyName, $e) {
-                var preventDefault;
-                switch (keyName) {
-                  case "up":
-                  case "down":
-                    preventDefault = !withModifier($e);
-                    break;
-
-                  default:
-                    preventDefault = false;
-                }
-                preventDefault && $e.preventDefault();
-            },
-            _shouldTrigger: function shouldTrigger(keyName, $e) {
-                var trigger;
-                switch (keyName) {
-                  case "tab":
-                    trigger = !withModifier($e);
-                    break;
-
-                  default:
-                    trigger = true;
-                }
-                return trigger;
-            },
-            _checkLanguageDirection: function checkLanguageDirection() {
-                var dir = (this.$input.css("direction") || "ltr").toLowerCase();
-                if (this.dir !== dir) {
-                    this.dir = dir;
-                    this.$hint.attr("dir", dir);
-                    this.trigger("langDirChanged", dir);
-                }
-            },
-            _setQuery: function setQuery(val, silent) {
-                var areEquivalent, hasDifferentWhitespace;
-                areEquivalent = areQueriesEquivalent(val, this.query);
-                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
-                this.query = val;
-                if (!silent && !areEquivalent) {
-                    this.trigger("queryChanged", this.query);
-                } else if (!silent && hasDifferentWhitespace) {
-                    this.trigger("whitespaceChanged", this.query);
-                }
-            },
-            bind: function() {
-                var that = this, onBlur, onFocus, onKeydown, onInput;
-                onBlur = _.bind(this._onBlur, this);
-                onFocus = _.bind(this._onFocus, this);
-                onKeydown = _.bind(this._onKeydown, this);
-                onInput = _.bind(this._onInput, this);
-                this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
-                if (!_.isMsie() || _.isMsie() > 9) {
-                    this.$input.on("input.tt", onInput);
-                } else {
-                    this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
-                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {
-                            return;
-                        }
-                        _.defer(_.bind(that._onInput, that, $e));
-                    });
-                }
-                return this;
-            },
-            focus: function focus() {
-                this.$input.focus();
-            },
-            blur: function blur() {
-                this.$input.blur();
-            },
-            getLangDir: function getLangDir() {
-                return this.dir;
-            },
-            getQuery: function getQuery() {
-                return this.query || "";
-            },
-            setQuery: function setQuery(val, silent) {
-                this.setInputValue(val);
-                this._setQuery(val, silent);
-            },
-            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
-                return this.query !== this.queryWhenFocused;
-            },
-            getInputValue: function getInputValue() {
-                return this.$input.val();
-            },
-            setInputValue: function setInputValue(value) {
-                this.$input.val(value);
-                this.clearHintIfInvalid();
-                this._checkLanguageDirection();
-            },
-            resetInputValue: function resetInputValue() {
-                this.setInputValue(this.query);
-            },
-            getHint: function getHint() {
-                return this.$hint.val();
-            },
-            setHint: function setHint(value) {
-                this.$hint.val(value);
-            },
-            clearHint: function clearHint() {
-                this.setHint("");
-            },
-            clearHintIfInvalid: function clearHintIfInvalid() {
-                var val, hint, valIsPrefixOfHint, isValid;
-                val = this.getInputValue();
-                hint = this.getHint();
-                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
-                isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
-                !isValid && this.clearHint();
-            },
-            hasFocus: function hasFocus() {
-                return this.$input.is(":focus");
-            },
-            hasOverflow: function hasOverflow() {
-                var constraint = this.$input.width() - 2;
-                this.$overflowHelper.text(this.getInputValue());
-                return this.$overflowHelper.width() >= constraint;
-            },
-            isCursorAtEnd: function() {
-                var valueLength, selectionStart, range;
-                valueLength = this.$input.val().length;
-                selectionStart = this.$input[0].selectionStart;
-                if (_.isNumber(selectionStart)) {
-                    return selectionStart === valueLength;
-                } else if (document.selection) {
-                    range = document.selection.createRange();
-                    range.moveStart("character", -valueLength);
-                    return valueLength === range.text.length;
-                }
-                return true;
-            },
-            destroy: function destroy() {
-                this.$hint.off(".tt");
-                this.$input.off(".tt");
-                this.$overflowHelper.remove();
-                this.$hint = this.$input = this.$overflowHelper = $("<div>");
-            }
-        });
-        return Input;
-        function buildOverflowHelper($input) {
-            return $('<pre aria-hidden="true"></pre>').css({
-                position: "absolute",
-                visibility: "hidden",
-                whiteSpace: "pre",
-                fontFamily: $input.css("font-family"),
-                fontSize: $input.css("font-size"),
-                fontStyle: $input.css("font-style"),
-                fontVariant: $input.css("font-variant"),
-                fontWeight: $input.css("font-weight"),
-                wordSpacing: $input.css("word-spacing"),
-                letterSpacing: $input.css("letter-spacing"),
-                textIndent: $input.css("text-indent"),
-                textRendering: $input.css("text-rendering"),
-                textTransform: $input.css("text-transform")
-            }).insertAfter($input);
-        }
-        function areQueriesEquivalent(a, b) {
-            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
-        }
-        function withModifier($e) {
-            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
-        }
-    }();
-    var Dataset = function() {
-        "use strict";
-        var keys, nameGenerator;
-        keys = {
-            val: "tt-selectable-display",
-            obj: "tt-selectable-object"
-        };
-        nameGenerator = _.getIdGenerator();
-        function Dataset(o, www) {
-            o = o || {};
-            o.templates = o.templates || {};
-            o.templates.notFound = o.templates.notFound || o.templates.empty;
-            if (!o.source) {
-                $.error("missing source");
-            }
-            if (!o.node) {
-                $.error("missing node");
-            }
-            if (o.name && !isValidName(o.name)) {
-                $.error("invalid dataset name: " + o.name);
-            }
-            www.mixin(this);
-            this.highlight = !!o.highlight;
-            this.name = o.name || nameGenerator();
-            this.limit = o.limit || 5;
-            this.displayFn = getDisplayFn(o.display || o.displayKey);
-            this.templates = getTemplates(o.templates, this.displayFn);
-            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
-            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
-            this._resetLastSuggestion();
-            this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
-        }
-        Dataset.extractData = function extractData(el) {
-            var $el = $(el);
-            if ($el.data(keys.obj)) {
-                return {
-                    val: $el.data(keys.val) || "",
-                    obj: $el.data(keys.obj) || null
-                };
-            }
-            return null;
-        };
-        _.mixin(Dataset.prototype, EventEmitter, {
-            _overwrite: function overwrite(query, suggestions) {
-                suggestions = suggestions || [];
-                if (suggestions.length) {
-                    this._renderSuggestions(query, suggestions);
-                } else if (this.async && this.templates.pending) {
-                    this._renderPending(query);
-                } else if (!this.async && this.templates.notFound) {
-                    this._renderNotFound(query);
-                } else {
-                    this._empty();
-                }
-                this.trigger("rendered", this.name, suggestions, false);
-            },
-            _append: function append(query, suggestions) {
-                suggestions = suggestions || [];
-                if (suggestions.length && this.$lastSuggestion.length) {
-                    this._appendSuggestions(query, suggestions);
-                } else if (suggestions.length) {
-                    this._renderSuggestions(query, suggestions);
-                } else if (!this.$lastSuggestion.length && this.templates.notFound) {
-                    this._renderNotFound(query);
-                }
-                this.trigger("rendered", this.name, suggestions, true);
-            },
-            _renderSuggestions: function renderSuggestions(query, suggestions) {
-                var $fragment;
-                $fragment = this._getSuggestionsFragment(query, suggestions);
-                this.$lastSuggestion = $fragment.children().last();
-                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
-            },
-            _appendSuggestions: function appendSuggestions(query, suggestions) {
-                var $fragment, $lastSuggestion;
-                $fragment = this._getSuggestionsFragment(query, suggestions);
-                $lastSuggestion = $fragment.children().last();
-                this.$lastSuggestion.after($fragment);
-                this.$lastSuggestion = $lastSuggestion;
-            },
-            _renderPending: function renderPending(query) {
-                var template = this.templates.pending;
-                this._resetLastSuggestion();
-                template && this.$el.html(template({
-                    query: query,
-                    dataset: this.name
-                }));
-            },
-            _renderNotFound: function renderNotFound(query) {
-                var template = this.templates.notFound;
-                this._resetLastSuggestion();
-                template && this.$el.html(template({
-                    query: query,
-                    dataset: this.name
-                }));
-            },
-            _empty: function empty() {
-                this.$el.empty();
-                this._resetLastSuggestion();
-            },
-            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
-                var that = this, fragment;
-                fragment = document.createDocumentFragment();
-                _.each(suggestions, function getSuggestionNode(suggestion) {
-                    var $el, context;
-                    context = that._injectQuery(query, suggestion);
-                    $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
-                    fragment.appendChild($el[0]);
-                });
-                this.highlight && highlight({
-                    className: this.classes.highlight,
-                    node: fragment,
-                    pattern: query
-                });
-                return $(fragment);
-            },
-            _getFooter: function getFooter(query, suggestions) {
-                return this.templates.footer ? this.templates.footer({
-                    query: query,
-                    suggestions: suggestions,
-                    dataset: this.name
-                }) : null;
-            },
-            _getHeader: function getHeader(query, suggestions) {
-                return this.templates.header ? this.templates.header({
-                    query: query,
-                    suggestions: suggestions,
-                    dataset: this.name
-                }) : null;
-            },
-            _resetLastSuggestion: function resetLastSuggestion() {
-                this.$lastSuggestion = $();
-            },
-            _injectQuery: function injectQuery(query, obj) {
-                return _.isObject(obj) ? _.mixin({
-                    _query: query
-                }, obj) : obj;
-            },
-            update: function update(query) {
-                var that = this, canceled = false, syncCalled = false, rendered = 0;
-                this.cancel();
-                this.cancel = function cancel() {
-                    canceled = true;
-                    that.cancel = $.noop;
-                    that.async && that.trigger("asyncCanceled", query);
-                };
-                this.source(query, sync, async);
-                !syncCalled && sync([]);
-                function sync(suggestions) {
-                    if (syncCalled) {
-                        return;
-                    }
-                    syncCalled = true;
-                    suggestions = (suggestions || []).slice(0, that.limit);
-                    rendered = suggestions.length;
-                    that._overwrite(query, suggestions);
-                    if (rendered < that.limit && that.async) {
-                        that.trigger("asyncRequested", query);
-                    }
-                }
-                function async(suggestions) {
-                    suggestions = suggestions || [];
-                    if (!canceled && rendered < that.limit) {
-                        that.cancel = $.noop;
-                        rendered += suggestions.length;
-                        that._append(query, suggestions.slice(0, that.limit - rendered));
-                        that.async && that.trigger("asyncReceived", query);
-                    }
-                }
-            },
-            cancel: $.noop,
-            clear: function clear() {
-                this._empty();
-                this.cancel();
-                this.trigger("cleared");
-            },
-            isEmpty: function isEmpty() {
-                return this.$el.is(":empty");
-            },
-            destroy: function destroy() {
-                this.$el = $("<div>");
-            }
-        });
-        return Dataset;
-        function getDisplayFn(display) {
-            display = display || _.stringify;
-            return _.isFunction(display) ? display : displayFn;
-            function displayFn(obj) {
-                return obj[display];
-            }
-        }
-        function getTemplates(templates, displayFn) {
-            return {
-                notFound: templates.notFound && _.templatify(templates.notFound),
-                pending: templates.pending && _.templatify(templates.pending),
-                header: templates.header && _.templatify(templates.header),
-                footer: templates.footer && _.templatify(templates.footer),
-                suggestion: templates.suggestion || suggestionTemplate
-            };
-            function suggestionTemplate(context) {
-                return $("<div>").text(displayFn(context));
-            }
-        }
-        function isValidName(str) {
-            return /^[_a-zA-Z0-9-]+$/.test(str);
-        }
-    }();
-    var Menu = function() {
-        "use strict";
-        function Menu(o, www) {
-            var that = this;
-            o = o || {};
-            if (!o.node) {
-                $.error("node is required");
-            }
-            www.mixin(this);
-            this.$node = $(o.node);
-            this.query = null;
-            this.datasets = _.map(o.datasets, initializeDataset);
-            function initializeDataset(oDataset) {
-                var node = that.$node.find(oDataset.node).first();
-                oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
-                return new Dataset(oDataset, www);
-            }
-        }
-        _.mixin(Menu.prototype, EventEmitter, {
-            _onSelectableClick: function onSelectableClick($e) {
-                this.trigger("selectableClicked", $($e.currentTarget));
-            },
-            _onRendered: function onRendered(type, dataset, suggestions, async) {
-                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-                this.trigger("datasetRendered", dataset, suggestions, async);
-            },
-            _onCleared: function onCleared() {
-                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-                this.trigger("datasetCleared");
-            },
-            _propagate: function propagate() {
-                this.trigger.apply(this, arguments);
-            },
-            _allDatasetsEmpty: function allDatasetsEmpty() {
-                return _.every(this.datasets, isDatasetEmpty);
-                function isDatasetEmpty(dataset) {
-                    return dataset.isEmpty();
-                }
-            },
-            _getSelectables: function getSelectables() {
-                return this.$node.find(this.selectors.selectable);
-            },
-            _removeCursor: function _removeCursor() {
-                var $selectable = this.getActiveSelectable();
-                $selectable && $selectable.removeClass(this.classes.cursor);
-            },
-            _ensureVisible: function ensureVisible($el) {
-                var elTop, elBottom, nodeScrollTop, nodeHeight;
-                elTop = $el.position().top;
-                elBottom = elTop + $el.outerHeight(true);
-                nodeScrollTop = this.$node.scrollTop();
-                nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
-                if (elTop < 0) {
-                    this.$node.scrollTop(nodeScrollTop + elTop);
-                } else if (nodeHeight < elBottom) {
-                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
-                }
-            },
-            bind: function() {
-                var that = this, onSelectableClick;
-                onSelectableClick = _.bind(this._onSelectableClick, this);
-                this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
-                _.each(this.datasets, function(dataset) {
-                    dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
-                });
-                return this;
-            },
-            isOpen: function isOpen() {
-                return this.$node.hasClass(this.classes.open);
-            },
-            open: function open() {
-                this.$node.addClass(this.classes.open);
-            },
-            close: function close() {
-                this.$node.removeClass(this.classes.open);
-                this._removeCursor();
-            },
-            setLanguageDirection: function setLanguageDirection(dir) {
-                this.$node.attr("dir", dir);
-            },
-            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
-                var $selectables, $oldCursor, oldIndex, newIndex;
-                $oldCursor = this.getActiveSelectable();
-                $selectables = this._getSelectables();
-                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
-                newIndex = oldIndex + delta;
-                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
-                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
-                return newIndex === -1 ? null : $selectables.eq(newIndex);
-            },
-            setCursor: function setCursor($selectable) {
-                this._removeCursor();
-                if ($selectable = $selectable && $selectable.first()) {
-                    $selectable.addClass(this.classes.cursor);
-                    this._ensureVisible($selectable);
-                }
-            },
-            getSelectableData: function getSelectableData($el) {
-                return $el && $el.length ? Dataset.extractData($el) : null;
-            },
-            getActiveSelectable: function getActiveSelectable() {
-                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
-                return $selectable.length ? $selectable : null;
-            },
-            getTopSelectable: function getTopSelectable() {
-                var $selectable = this._getSelectables().first();
-                return $selectable.length ? $selectable : null;
-            },
-            update: function update(query) {
-                var isValidUpdate = query !== this.query;
-                if (isValidUpdate) {
-                    this.query = query;
-                    _.each(this.datasets, updateDataset);
-                }
-                return isValidUpdate;
-                function updateDataset(dataset) {
-                    dataset.update(query);
-                }
-            },
-            empty: function empty() {
-                _.each(this.datasets, clearDataset);
-                this.query = null;
-                this.$node.addClass(this.classes.empty);
-                function clearDataset(dataset) {
-                    dataset.clear();
-                }
-            },
-            destroy: function destroy() {
-                this.$node.off(".tt");
-                this.$node = $("<div>");
-                _.each(this.datasets, destroyDataset);
-                function destroyDataset(dataset) {
-                    dataset.destroy();
-                }
-            }
-        });
-        return Menu;
-    }();
-    var DefaultMenu = function() {
-        "use strict";
-        var s = Menu.prototype;
-        function DefaultMenu() {
-            Menu.apply(this, [].slice.call(arguments, 0));
-        }
-        _.mixin(DefaultMenu.prototype, Menu.prototype, {
-            open: function open() {
-                !this._allDatasetsEmpty() && this._show();
-                return s.open.apply(this, [].slice.call(arguments, 0));
-            },
-            close: function close() {
-                this._hide();
-                return s.close.apply(this, [].slice.call(arguments, 0));
-            },
-            _onRendered: function onRendered() {
-                if (this._allDatasetsEmpty()) {
-                    this._hide();
-                } else {
-                    this.isOpen() && this._show();
-                }
-                return s._onRendered.apply(this, [].slice.call(arguments, 0));
-            },
-            _onCleared: function onCleared() {
-                if (this._allDatasetsEmpty()) {
-                    this._hide();
-                } else {
-                    this.isOpen() && this._show();
-                }
-                return s._onCleared.apply(this, [].slice.call(arguments, 0));
-            },
-            setLanguageDirection: function setLanguageDirection(dir) {
-                this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
-                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
-            },
-            _hide: function hide() {
-                this.$node.hide();
-            },
-            _show: function show() {
-                this.$node.css("display", "block");
-            }
-        });
-        return DefaultMenu;
-    }();
-    var Typeahead = function() {
-        "use strict";
-        function Typeahead(o, www) {
-            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
-            o = o || {};
-            if (!o.input) {
-                $.error("missing input");
-            }
-            if (!o.menu) {
-                $.error("missing menu");
-            }
-            if (!o.eventBus) {
-                $.error("missing event bus");
-            }
-            www.mixin(this);
-            this.eventBus = o.eventBus;
-            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
-            this.input = o.input;
-            this.menu = o.menu;
-            this.enabled = true;
-            this.active = false;
-            this.input.hasFocus() && this.activate();
-            this.dir = this.input.getLangDir();
-            this._hacks();
-            this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
-            onFocused = c(this, "activate", "open", "_onFocused");
-            onBlurred = c(this, "deactivate", "_onBlurred");
-            onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
-            onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
-            onEscKeyed = c(this, "isActive", "_onEscKeyed");
-            onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
-            onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
-            onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
-            onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
-            onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
-            onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
-            this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
-        }
-        _.mixin(Typeahead.prototype, {
-            _hacks: function hacks() {
-                var $input, $menu;
-                $input = this.input.$input || $("<div>");
-                $menu = this.menu.$node || $("<div>");
-                $input.on("blur.tt", function($e) {
-                    var active, isActive, hasActive;
-                    active = document.activeElement;
-                    isActive = $menu.is(active);
-                    hasActive = $menu.has(active).length > 0;
-                    if (_.isMsie() && (isActive || hasActive)) {
-                        $e.preventDefault();
-                        $e.stopImmediatePropagation();
-                        _.defer(function() {
-                            $input.focus();
-                        });
-                    }
-                });
-                $menu.on("mousedown.tt", function($e) {
-                    $e.preventDefault();
-                });
-            },
-            _onSelectableClicked: function onSelectableClicked(type, $el) {
-                this.select($el);
-            },
-            _onDatasetCleared: function onDatasetCleared() {
-                this._updateHint();
-            },
-            _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
-                this._updateHint();
-                this.eventBus.trigger("render", suggestions, async, dataset);
-            },
-            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
-                this.eventBus.trigger("asyncrequest", query, dataset);
-            },
-            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
-                this.eventBus.trigger("asynccancel", query, dataset);
-            },
-            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
-                this.eventBus.trigger("asyncreceive", query, dataset);
-            },
-            _onFocused: function onFocused() {
-                this._minLengthMet() && this.menu.update(this.input.getQuery());
-            },
-            _onBlurred: function onBlurred() {
-                if (this.input.hasQueryChangedSinceLastFocus()) {
-                    this.eventBus.trigger("change", this.input.getQuery());
-                }
-            },
-            _onEnterKeyed: function onEnterKeyed(type, $e) {
-                var $selectable;
-                if ($selectable = this.menu.getActiveSelectable()) {
-                    this.select($selectable) && $e.preventDefault();
-                }
-            },
-            _onTabKeyed: function onTabKeyed(type, $e) {
-                var $selectable;
-                if ($selectable = this.menu.getActiveSelectable()) {
-                    this.select($selectable) && $e.preventDefault();
-                } else if ($selectable = this.menu.getTopSelectable()) {
-                    this.autocomplete($selectable) && $e.preventDefault();
-                }
-            },
-            _onEscKeyed: function onEscKeyed() {
-                this.close();
-            },
-            _onUpKeyed: function onUpKeyed() {
-                this.moveCursor(-1);
-            },
-            _onDownKeyed: function onDownKeyed() {
-                this.moveCursor(+1);
-            },
-            _onLeftKeyed: function onLeftKeyed() {
-                if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
-                    this.autocomplete(this.menu.getTopSelectable());
-                }
-            },
-            _onRightKeyed: function onRightKeyed() {
-                if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
-                    this.autocomplete(this.menu.getTopSelectable());
-                }
-            },
-            _onQueryChanged: function onQueryChanged(e, query) {
-                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
-            },
-            _onWhitespaceChanged: function onWhitespaceChanged() {
-                this._updateHint();
-            },
-            _onLangDirChanged: function onLangDirChanged(e, dir) {
-                if (this.dir !== dir) {
-                    this.dir = dir;
-                    this.menu.setLanguageDirection(dir);
-                }
-            },
-            _openIfActive: function openIfActive() {
-                this.isActive() && this.open();
-            },
-            _minLengthMet: function minLengthMet(query) {
-                query = _.isString(query) ? query : this.input.getQuery() || "";
-                return query.length >= this.minLength;
-            },
-            _updateHint: function updateHint() {
-                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
-                $selectable = this.menu.getTopSelectable();
-                data = this.menu.getSelectableData($selectable);
-                val = this.input.getInputValue();
-                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
-                    query = Input.normalizeQuery(val);
-                    escapedQuery = _.escapeRegExChars(query);
-                    frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
-                    match = frontMatchRegEx.exec(data.val);
-                    match && this.input.setHint(val + match[1]);
-                } else {
-                    this.input.clearHint();
-                }
-            },
-            isEnabled: function isEnabled() {
-                return this.enabled;
-            },
-            enable: function enable() {
-                this.enabled = true;
-            },
-            disable: function disable() {
-                this.enabled = false;
-            },
-            isActive: function isActive() {
-                return this.active;
-            },
-            activate: function activate() {
-                if (this.isActive()) {
-                    return true;
-                } else if (!this.isEnabled() || this.eventBus.before("active")) {
-                    return false;
-                } else {
-                    this.active = true;
-                    this.eventBus.trigger("active");
-                    return true;
-                }
-            },
-            deactivate: function deactivate() {
-                if (!this.isActive()) {
-                    return true;
-                } else if (this.eventBus.before("idle")) {
-                    return false;
-                } else {
-                    this.active = false;
-                    this.close();
-                    this.eventBus.trigger("idle");
-                    return true;
-                }
-            },
-            isOpen: function isOpen() {
-                return this.menu.isOpen();
-            },
-            open: function open() {
-                if (!this.isOpen() && !this.eventBus.before("open")) {
-                    this.menu.open();
-                    this._updateHint();
-                    this.eventBus.trigger("open");
-                }
-                return this.isOpen();
-            },
-            close: function close() {
-                if (this.isOpen() && !this.eventBus.before("close")) {
-                    this.menu.close();
-                    this.input.clearHint();
-                    this.input.resetInputValue();
-                    this.eventBus.trigger("close");
-                }
-                return !this.isOpen();
-            },
-            setVal: function setVal(val) {
-                this.input.setQuery(_.toStr(val));
-            },
-            getVal: function getVal() {
-                return this.input.getQuery();
-            },
-            select: function select($selectable) {
-                var data = this.menu.getSelectableData($selectable);
-                if (data && !this.eventBus.before("select", data.obj)) {
-                    this.input.setQuery(data.val, true);
-                    this.eventBus.trigger("select", data.obj);
-                    this.close();
-                    return true;
-                }
-                return false;
-            },
-            autocomplete: function autocomplete($selectable) {
-                var query, data, isValid;
-                query = this.input.getQuery();
-                data = this.menu.getSelectableData($selectable);
-                isValid = data && query !== data.val;
-                if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
-                    this.input.setQuery(data.val);
-                    this.eventBus.trigger("autocomplete", data.obj);
-                    return true;
-                }
-                return false;
-            },
-            moveCursor: function moveCursor(delta) {
-                var query, $candidate, data, payload, cancelMove;
-                query = this.input.getQuery();
-                $candidate = this.menu.selectableRelativeToCursor(delta);
-                data = this.menu.getSelectableData($candidate);
-                payload = data ? data.obj : null;
-                cancelMove = this._minLengthMet() && this.menu.update(query);
-                if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
-                    this.menu.setCursor($candidate);
-                    if (data) {
-                        this.input.setInputValue(data.val);
-                    } else {
-                        this.input.resetInputValue();
-                        this._updateHint();
-                    }
-                    this.eventBus.trigger("cursorchange", payload);
-                    return true;
-                }
-                return false;
-            },
-            destroy: function destroy() {
-                this.input.destroy();
-                this.menu.destroy();
-            }
-        });
-        return Typeahead;
-        function c(ctx) {
-            var methods = [].slice.call(arguments, 1);
-            return function() {
-                var args = [].slice.call(arguments);
-                _.each(methods, function(method) {
-                    return ctx[method].apply(ctx, args);
-                });
-            };
-        }
-    }();
-    (function() {
-        "use strict";
-        var old, keys, methods;
-        old = $.fn.typeahead;
-        keys = {
-            www: "tt-www",
-            attrs: "tt-attrs",
-            typeahead: "tt-typeahead"
-        };
-        methods = {
-            initialize: function initialize(o, datasets) {
-                var www;
-                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
-                o = o || {};
-                www = WWW(o.classNames);
-                return this.each(attach);
-                function attach() {
-                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;
-                    _.each(datasets, function(d) {
-                        d.highlight = !!o.highlight;
-                    });
-                    $input = $(this);
-                    $wrapper = $(www.html.wrapper);
-                    $hint = $elOrNull(o.hint);
-                    $menu = $elOrNull(o.menu);
-                    defaultHint = o.hint !== false && !$hint;
-                    defaultMenu = o.menu !== false && !$menu;
-                    defaultHint && ($hint = buildHintFromInput($input, www));
-                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
-                    $hint && $hint.val("");
-                    $input = prepInput($input, www);
-                    if (defaultHint || defaultMenu) {
-                        $wrapper.css(www.css.wrapper);
-                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
-                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
-                    }
-                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;
-                    eventBus = new EventBus({
-                        el: $input
-                    });
-                    input = new Input({
-                        hint: $hint,
-                        input: $input
-                    }, www);
-                    menu = new MenuConstructor({
-                        node: $menu,
-                        datasets: datasets
-                    }, www);
-                    typeahead = new Typeahead({
-                        input: input,
-                        menu: menu,
-                        eventBus: eventBus,
-                        minLength: o.minLength
-                    }, www);
-                    $input.data(keys.www, www);
-                    $input.data(keys.typeahead, typeahead);
-                }
-            },
-            isEnabled: function isEnabled() {
-                var enabled;
-                ttEach(this.first(), function(t) {
-                    enabled = t.isEnabled();
-                });
-                return enabled;
-            },
-            enable: function enable() {
-                ttEach(this, function(t) {
-                    t.enable();
-                });
-                return this;
-            },
-            disable: function disable() {
-                ttEach(this, function(t) {
-                    t.disable();
-                });
-                return this;
-            },
-            isActive: function isActive() {
-                var active;
-                ttEach(this.first(), function(t) {
-                    active = t.isActive();
-                });
-                return active;
-            },
-            activate: function activate() {
-                ttEach(this, function(t) {
-                    t.activate();
-                });
-                return this;
-            },
-            deactivate: function deactivate() {
-                ttEach(this, function(t) {
-                    t.deactivate();
-                });
-                return this;
-            },
-            isOpen: function isOpen() {
-                var open;
-                ttEach(this.first(), function(t) {
-                    open = t.isOpen();
-                });
-                return open;
-            },
-            open: function open() {
-                ttEach(this, function(t) {
-                    t.open();
-                });
-                return this;
-            },
-            close: function close() {
-                ttEach(this, function(t) {
-                    t.close();
-                });
-                return this;
-            },
-            select: function select(el) {
-                var success = false, $el = $(el);
-                ttEach(this.first(), function(t) {
-                    success = t.select($el);
-                });
-                return success;
-            },
-            autocomplete: function autocomplete(el) {
-                var success = false, $el = $(el);
-                ttEach(this.first(), function(t) {
-                    success = t.autocomplete($el);
-                });
-                return success;
-            },
-            moveCursor: function moveCursoe(delta) {
-                var success = false;
-                ttEach(this.first(), function(t) {
-                    success = t.moveCursor(delta);
-                });
-                return success;
-            },
-            val: function val(newVal) {
-                var query;
-                if (!arguments.length) {
-                    ttEach(this.first(), function(t) {
-                        query = t.getVal();
-                    });
-                    return query;
-                } else {
-                    ttEach(this, function(t) {
-                        t.setVal(newVal);
-                    });
-                    return this;
-                }
-            },
-            destroy: function destroy() {
-                ttEach(this, function(typeahead, $input) {
-                    revert($input);
-                    typeahead.destroy();
-                });
-                return this;
-            }
-        };
-        $.fn.typeahead = function(method) {
-            if (methods[method]) {
-                return methods[method].apply(this, [].slice.call(arguments, 1));
-            } else {
-                return methods.initialize.apply(this, arguments);
-            }
-        };
-        $.fn.typeahead.noConflict = function noConflict() {
-            $.fn.typeahead = old;
-            return this;
-        };
-        function ttEach($els, fn) {
-            $els.each(function() {
-                var $input = $(this), typeahead;
-                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
-            });
-        }
-        function buildHintFromInput($input, www) {
-            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
-                autocomplete: "off",
-                spellcheck: "false",
-                tabindex: -1
-            });
-        }
-        function prepInput($input, www) {
-            $input.data(keys.attrs, {
-                dir: $input.attr("dir"),
-                autocomplete: $input.attr("autocomplete"),
-                spellcheck: $input.attr("spellcheck"),
-                style: $input.attr("style")
-            });
-            $input.addClass(www.classes.input).attr({
-                autocomplete: "off",
-                spellcheck: false
-            });
-            try {
-                !$input.attr("dir") && $input.attr("dir", "auto");
-            } catch (e) {}
-            return $input;
-        }
-        function getBackgroundStyles($el) {
-            return {
-                backgroundAttachment: $el.css("background-attachment"),
-                backgroundClip: $el.css("background-clip"),
-                backgroundColor: $el.css("background-color"),
-                backgroundImage: $el.css("background-image"),
-                backgroundOrigin: $el.css("background-origin"),
-                backgroundPosition: $el.css("background-position"),
-                backgroundRepeat: $el.css("background-repeat"),
-                backgroundSize: $el.css("background-size")
-            };
-        }
-        function revert($input) {
-            var www, $wrapper;
-            www = $input.data(keys.www);
-            $wrapper = $input.parent().filter(www.selectors.wrapper);
-            _.each($input.data(keys.attrs), function(val, key) {
-                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
-            });
-            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
-            if ($wrapper.length) {
-                $input.detach().insertAfter($wrapper);
-                $wrapper.remove();
-            }
-        }
-        function $elOrNull(obj) {
-            var isValid, $el;
-            isValid = _.isJQuery(obj) || _.isElement(obj);
-            $el = isValid ? $(obj).first() : [];
-            return $el.length ? $el : null;
-        }
-    })();
-});

Разлика између датотеке није приказан због своје велике величине
+ 0 - 6
vendor/bower-asset/typeahead.js/dist/typeahead.bundle.min.js


+ 0 - 1538
vendor/bower-asset/typeahead.js/dist/typeahead.jquery.js

@@ -1,1538 +0,0 @@
-/*!
- * typeahead.js 0.11.1
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-(function(root, factory) {
-    if (typeof define === "function" && define.amd) {
-        define("typeahead.js", [ "jquery" ], function(a0) {
-            return factory(a0);
-        });
-    } else if (typeof exports === "object") {
-        module.exports = factory(require("jquery"));
-    } else {
-        factory(jQuery);
-    }
-})(this, function($) {
-    var _ = function() {
-        "use strict";
-        return {
-            isMsie: function() {
-                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
-            },
-            isBlankString: function(str) {
-                return !str || /^\s*$/.test(str);
-            },
-            escapeRegExChars: function(str) {
-                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-            },
-            isString: function(obj) {
-                return typeof obj === "string";
-            },
-            isNumber: function(obj) {
-                return typeof obj === "number";
-            },
-            isArray: $.isArray,
-            isFunction: $.isFunction,
-            isObject: $.isPlainObject,
-            isUndefined: function(obj) {
-                return typeof obj === "undefined";
-            },
-            isElement: function(obj) {
-                return !!(obj && obj.nodeType === 1);
-            },
-            isJQuery: function(obj) {
-                return obj instanceof $;
-            },
-            toStr: function toStr(s) {
-                return _.isUndefined(s) || s === null ? "" : s + "";
-            },
-            bind: $.proxy,
-            each: function(collection, cb) {
-                $.each(collection, reverseArgs);
-                function reverseArgs(index, value) {
-                    return cb(value, index);
-                }
-            },
-            map: $.map,
-            filter: $.grep,
-            every: function(obj, test) {
-                var result = true;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (!(result = test.call(null, val, key, obj))) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            some: function(obj, test) {
-                var result = false;
-                if (!obj) {
-                    return result;
-                }
-                $.each(obj, function(key, val) {
-                    if (result = test.call(null, val, key, obj)) {
-                        return false;
-                    }
-                });
-                return !!result;
-            },
-            mixin: $.extend,
-            identity: function(x) {
-                return x;
-            },
-            clone: function(obj) {
-                return $.extend(true, {}, obj);
-            },
-            getIdGenerator: function() {
-                var counter = 0;
-                return function() {
-                    return counter++;
-                };
-            },
-            templatify: function templatify(obj) {
-                return $.isFunction(obj) ? obj : template;
-                function template() {
-                    return String(obj);
-                }
-            },
-            defer: function(fn) {
-                setTimeout(fn, 0);
-            },
-            debounce: function(func, wait, immediate) {
-                var timeout, result;
-                return function() {
-                    var context = this, args = arguments, later, callNow;
-                    later = function() {
-                        timeout = null;
-                        if (!immediate) {
-                            result = func.apply(context, args);
-                        }
-                    };
-                    callNow = immediate && !timeout;
-                    clearTimeout(timeout);
-                    timeout = setTimeout(later, wait);
-                    if (callNow) {
-                        result = func.apply(context, args);
-                    }
-                    return result;
-                };
-            },
-            throttle: function(func, wait) {
-                var context, args, timeout, result, previous, later;
-                previous = 0;
-                later = function() {
-                    previous = new Date();
-                    timeout = null;
-                    result = func.apply(context, args);
-                };
-                return function() {
-                    var now = new Date(), remaining = wait - (now - previous);
-                    context = this;
-                    args = arguments;
-                    if (remaining <= 0) {
-                        clearTimeout(timeout);
-                        timeout = null;
-                        previous = now;
-                        result = func.apply(context, args);
-                    } else if (!timeout) {
-                        timeout = setTimeout(later, remaining);
-                    }
-                    return result;
-                };
-            },
-            stringify: function(val) {
-                return _.isString(val) ? val : JSON.stringify(val);
-            },
-            noop: function() {}
-        };
-    }();
-    var WWW = function() {
-        "use strict";
-        var defaultClassNames = {
-            wrapper: "twitter-typeahead",
-            input: "tt-input",
-            hint: "tt-hint",
-            menu: "tt-menu",
-            dataset: "tt-dataset",
-            suggestion: "tt-suggestion",
-            selectable: "tt-selectable",
-            empty: "tt-empty",
-            open: "tt-open",
-            cursor: "tt-cursor",
-            highlight: "tt-highlight"
-        };
-        return build;
-        function build(o) {
-            var www, classes;
-            classes = _.mixin({}, defaultClassNames, o);
-            www = {
-                css: buildCss(),
-                classes: classes,
-                html: buildHtml(classes),
-                selectors: buildSelectors(classes)
-            };
-            return {
-                css: www.css,
-                html: www.html,
-                classes: www.classes,
-                selectors: www.selectors,
-                mixin: function(o) {
-                    _.mixin(o, www);
-                }
-            };
-        }
-        function buildHtml(c) {
-            return {
-                wrapper: '<span class="' + c.wrapper + '"></span>',
-                menu: '<div class="' + c.menu + '"></div>'
-            };
-        }
-        function buildSelectors(classes) {
-            var selectors = {};
-            _.each(classes, function(v, k) {
-                selectors[k] = "." + v;
-            });
-            return selectors;
-        }
-        function buildCss() {
-            var css = {
-                wrapper: {
-                    position: "relative",
-                    display: "inline-block"
-                },
-                hint: {
-                    position: "absolute",
-                    top: "0",
-                    left: "0",
-                    borderColor: "transparent",
-                    boxShadow: "none",
-                    opacity: "1"
-                },
-                input: {
-                    position: "relative",
-                    verticalAlign: "top",
-                    backgroundColor: "transparent"
-                },
-                inputWithNoHint: {
-                    position: "relative",
-                    verticalAlign: "top"
-                },
-                menu: {
-                    position: "absolute",
-                    top: "100%",
-                    left: "0",
-                    zIndex: "100",
-                    display: "none"
-                },
-                ltr: {
-                    left: "0",
-                    right: "auto"
-                },
-                rtl: {
-                    left: "auto",
-                    right: " 0"
-                }
-            };
-            if (_.isMsie()) {
-                _.mixin(css.input, {
-                    backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
-                });
-            }
-            return css;
-        }
-    }();
-    var EventBus = function() {
-        "use strict";
-        var namespace, deprecationMap;
-        namespace = "typeahead:";
-        deprecationMap = {
-            render: "rendered",
-            cursorchange: "cursorchanged",
-            select: "selected",
-            autocomplete: "autocompleted"
-        };
-        function EventBus(o) {
-            if (!o || !o.el) {
-                $.error("EventBus initialized without el");
-            }
-            this.$el = $(o.el);
-        }
-        _.mixin(EventBus.prototype, {
-            _trigger: function(type, args) {
-                var $e;
-                $e = $.Event(namespace + type);
-                (args = args || []).unshift($e);
-                this.$el.trigger.apply(this.$el, args);
-                return $e;
-            },
-            before: function(type) {
-                var args, $e;
-                args = [].slice.call(arguments, 1);
-                $e = this._trigger("before" + type, args);
-                return $e.isDefaultPrevented();
-            },
-            trigger: function(type) {
-                var deprecatedType;
-                this._trigger(type, [].slice.call(arguments, 1));
-                if (deprecatedType = deprecationMap[type]) {
-                    this._trigger(deprecatedType, [].slice.call(arguments, 1));
-                }
-            }
-        });
-        return EventBus;
-    }();
-    var EventEmitter = function() {
-        "use strict";
-        var splitter = /\s+/, nextTick = getNextTick();
-        return {
-            onSync: onSync,
-            onAsync: onAsync,
-            off: off,
-            trigger: trigger
-        };
-        function on(method, types, cb, context) {
-            var type;
-            if (!cb) {
-                return this;
-            }
-            types = types.split(splitter);
-            cb = context ? bindContext(cb, context) : cb;
-            this._callbacks = this._callbacks || {};
-            while (type = types.shift()) {
-                this._callbacks[type] = this._callbacks[type] || {
-                    sync: [],
-                    async: []
-                };
-                this._callbacks[type][method].push(cb);
-            }
-            return this;
-        }
-        function onAsync(types, cb, context) {
-            return on.call(this, "async", types, cb, context);
-        }
-        function onSync(types, cb, context) {
-            return on.call(this, "sync", types, cb, context);
-        }
-        function off(types) {
-            var type;
-            if (!this._callbacks) {
-                return this;
-            }
-            types = types.split(splitter);
-            while (type = types.shift()) {
-                delete this._callbacks[type];
-            }
-            return this;
-        }
-        function trigger(types) {
-            var type, callbacks, args, syncFlush, asyncFlush;
-            if (!this._callbacks) {
-                return this;
-            }
-            types = types.split(splitter);
-            args = [].slice.call(arguments, 1);
-            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
-                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
-                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
-                syncFlush() && nextTick(asyncFlush);
-            }
-            return this;
-        }
-        function getFlush(callbacks, context, args) {
-            return flush;
-            function flush() {
-                var cancelled;
-                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
-                    cancelled = callbacks[i].apply(context, args) === false;
-                }
-                return !cancelled;
-            }
-        }
-        function getNextTick() {
-            var nextTickFn;
-            if (window.setImmediate) {
-                nextTickFn = function nextTickSetImmediate(fn) {
-                    setImmediate(function() {
-                        fn();
-                    });
-                };
-            } else {
-                nextTickFn = function nextTickSetTimeout(fn) {
-                    setTimeout(function() {
-                        fn();
-                    }, 0);
-                };
-            }
-            return nextTickFn;
-        }
-        function bindContext(fn, context) {
-            return fn.bind ? fn.bind(context) : function() {
-                fn.apply(context, [].slice.call(arguments, 0));
-            };
-        }
-    }();
-    var highlight = function(doc) {
-        "use strict";
-        var defaults = {
-            node: null,
-            pattern: null,
-            tagName: "strong",
-            className: null,
-            wordsOnly: false,
-            caseSensitive: false
-        };
-        return function hightlight(o) {
-            var regex;
-            o = _.mixin({}, defaults, o);
-            if (!o.node || !o.pattern) {
-                return;
-            }
-            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
-            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
-            traverse(o.node, hightlightTextNode);
-            function hightlightTextNode(textNode) {
-                var match, patternNode, wrapperNode;
-                if (match = regex.exec(textNode.data)) {
-                    wrapperNode = doc.createElement(o.tagName);
-                    o.className && (wrapperNode.className = o.className);
-                    patternNode = textNode.splitText(match.index);
-                    patternNode.splitText(match[0].length);
-                    wrapperNode.appendChild(patternNode.cloneNode(true));
-                    textNode.parentNode.replaceChild(wrapperNode, patternNode);
-                }
-                return !!match;
-            }
-            function traverse(el, hightlightTextNode) {
-                var childNode, TEXT_NODE_TYPE = 3;
-                for (var i = 0; i < el.childNodes.length; i++) {
-                    childNode = el.childNodes[i];
-                    if (childNode.nodeType === TEXT_NODE_TYPE) {
-                        i += hightlightTextNode(childNode) ? 1 : 0;
-                    } else {
-                        traverse(childNode, hightlightTextNode);
-                    }
-                }
-            }
-        };
-        function getRegex(patterns, caseSensitive, wordsOnly) {
-            var escapedPatterns = [], regexStr;
-            for (var i = 0, len = patterns.length; i < len; i++) {
-                escapedPatterns.push(_.escapeRegExChars(patterns[i]));
-            }
-            regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
-            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
-        }
-    }(window.document);
-    var Input = function() {
-        "use strict";
-        var specialKeyCodeMap;
-        specialKeyCodeMap = {
-            9: "tab",
-            27: "esc",
-            37: "left",
-            39: "right",
-            13: "enter",
-            38: "up",
-            40: "down"
-        };
-        function Input(o, www) {
-            o = o || {};
-            if (!o.input) {
-                $.error("input is missing");
-            }
-            www.mixin(this);
-            this.$hint = $(o.hint);
-            this.$input = $(o.input);
-            this.query = this.$input.val();
-            this.queryWhenFocused = this.hasFocus() ? this.query : null;
-            this.$overflowHelper = buildOverflowHelper(this.$input);
-            this._checkLanguageDirection();
-            if (this.$hint.length === 0) {
-                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
-            }
-        }
-        Input.normalizeQuery = function(str) {
-            return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
-        };
-        _.mixin(Input.prototype, EventEmitter, {
-            _onBlur: function onBlur() {
-                this.resetInputValue();
-                this.trigger("blurred");
-            },
-            _onFocus: function onFocus() {
-                this.queryWhenFocused = this.query;
-                this.trigger("focused");
-            },
-            _onKeydown: function onKeydown($e) {
-                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
-                this._managePreventDefault(keyName, $e);
-                if (keyName && this._shouldTrigger(keyName, $e)) {
-                    this.trigger(keyName + "Keyed", $e);
-                }
-            },
-            _onInput: function onInput() {
-                this._setQuery(this.getInputValue());
-                this.clearHintIfInvalid();
-                this._checkLanguageDirection();
-            },
-            _managePreventDefault: function managePreventDefault(keyName, $e) {
-                var preventDefault;
-                switch (keyName) {
-                  case "up":
-                  case "down":
-                    preventDefault = !withModifier($e);
-                    break;
-
-                  default:
-                    preventDefault = false;
-                }
-                preventDefault && $e.preventDefault();
-            },
-            _shouldTrigger: function shouldTrigger(keyName, $e) {
-                var trigger;
-                switch (keyName) {
-                  case "tab":
-                    trigger = !withModifier($e);
-                    break;
-
-                  default:
-                    trigger = true;
-                }
-                return trigger;
-            },
-            _checkLanguageDirection: function checkLanguageDirection() {
-                var dir = (this.$input.css("direction") || "ltr").toLowerCase();
-                if (this.dir !== dir) {
-                    this.dir = dir;
-                    this.$hint.attr("dir", dir);
-                    this.trigger("langDirChanged", dir);
-                }
-            },
-            _setQuery: function setQuery(val, silent) {
-                var areEquivalent, hasDifferentWhitespace;
-                areEquivalent = areQueriesEquivalent(val, this.query);
-                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
-                this.query = val;
-                if (!silent && !areEquivalent) {
-                    this.trigger("queryChanged", this.query);
-                } else if (!silent && hasDifferentWhitespace) {
-                    this.trigger("whitespaceChanged", this.query);
-                }
-            },
-            bind: function() {
-                var that = this, onBlur, onFocus, onKeydown, onInput;
-                onBlur = _.bind(this._onBlur, this);
-                onFocus = _.bind(this._onFocus, this);
-                onKeydown = _.bind(this._onKeydown, this);
-                onInput = _.bind(this._onInput, this);
-                this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
-                if (!_.isMsie() || _.isMsie() > 9) {
-                    this.$input.on("input.tt", onInput);
-                } else {
-                    this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
-                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {
-                            return;
-                        }
-                        _.defer(_.bind(that._onInput, that, $e));
-                    });
-                }
-                return this;
-            },
-            focus: function focus() {
-                this.$input.focus();
-            },
-            blur: function blur() {
-                this.$input.blur();
-            },
-            getLangDir: function getLangDir() {
-                return this.dir;
-            },
-            getQuery: function getQuery() {
-                return this.query || "";
-            },
-            setQuery: function setQuery(val, silent) {
-                this.setInputValue(val);
-                this._setQuery(val, silent);
-            },
-            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
-                return this.query !== this.queryWhenFocused;
-            },
-            getInputValue: function getInputValue() {
-                return this.$input.val();
-            },
-            setInputValue: function setInputValue(value) {
-                this.$input.val(value);
-                this.clearHintIfInvalid();
-                this._checkLanguageDirection();
-            },
-            resetInputValue: function resetInputValue() {
-                this.setInputValue(this.query);
-            },
-            getHint: function getHint() {
-                return this.$hint.val();
-            },
-            setHint: function setHint(value) {
-                this.$hint.val(value);
-            },
-            clearHint: function clearHint() {
-                this.setHint("");
-            },
-            clearHintIfInvalid: function clearHintIfInvalid() {
-                var val, hint, valIsPrefixOfHint, isValid;
-                val = this.getInputValue();
-                hint = this.getHint();
-                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
-                isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
-                !isValid && this.clearHint();
-            },
-            hasFocus: function hasFocus() {
-                return this.$input.is(":focus");
-            },
-            hasOverflow: function hasOverflow() {
-                var constraint = this.$input.width() - 2;
-                this.$overflowHelper.text(this.getInputValue());
-                return this.$overflowHelper.width() >= constraint;
-            },
-            isCursorAtEnd: function() {
-                var valueLength, selectionStart, range;
-                valueLength = this.$input.val().length;
-                selectionStart = this.$input[0].selectionStart;
-                if (_.isNumber(selectionStart)) {
-                    return selectionStart === valueLength;
-                } else if (document.selection) {
-                    range = document.selection.createRange();
-                    range.moveStart("character", -valueLength);
-                    return valueLength === range.text.length;
-                }
-                return true;
-            },
-            destroy: function destroy() {
-                this.$hint.off(".tt");
-                this.$input.off(".tt");
-                this.$overflowHelper.remove();
-                this.$hint = this.$input = this.$overflowHelper = $("<div>");
-            }
-        });
-        return Input;
-        function buildOverflowHelper($input) {
-            return $('<pre aria-hidden="true"></pre>').css({
-                position: "absolute",
-                visibility: "hidden",
-                whiteSpace: "pre",
-                fontFamily: $input.css("font-family"),
-                fontSize: $input.css("font-size"),
-                fontStyle: $input.css("font-style"),
-                fontVariant: $input.css("font-variant"),
-                fontWeight: $input.css("font-weight"),
-                wordSpacing: $input.css("word-spacing"),
-                letterSpacing: $input.css("letter-spacing"),
-                textIndent: $input.css("text-indent"),
-                textRendering: $input.css("text-rendering"),
-                textTransform: $input.css("text-transform")
-            }).insertAfter($input);
-        }
-        function areQueriesEquivalent(a, b) {
-            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
-        }
-        function withModifier($e) {
-            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
-        }
-    }();
-    var Dataset = function() {
-        "use strict";
-        var keys, nameGenerator;
-        keys = {
-            val: "tt-selectable-display",
-            obj: "tt-selectable-object"
-        };
-        nameGenerator = _.getIdGenerator();
-        function Dataset(o, www) {
-            o = o || {};
-            o.templates = o.templates || {};
-            o.templates.notFound = o.templates.notFound || o.templates.empty;
-            if (!o.source) {
-                $.error("missing source");
-            }
-            if (!o.node) {
-                $.error("missing node");
-            }
-            if (o.name && !isValidName(o.name)) {
-                $.error("invalid dataset name: " + o.name);
-            }
-            www.mixin(this);
-            this.highlight = !!o.highlight;
-            this.name = o.name || nameGenerator();
-            this.limit = o.limit || 5;
-            this.displayFn = getDisplayFn(o.display || o.displayKey);
-            this.templates = getTemplates(o.templates, this.displayFn);
-            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
-            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
-            this._resetLastSuggestion();
-            this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
-        }
-        Dataset.extractData = function extractData(el) {
-            var $el = $(el);
-            if ($el.data(keys.obj)) {
-                return {
-                    val: $el.data(keys.val) || "",
-                    obj: $el.data(keys.obj) || null
-                };
-            }
-            return null;
-        };
-        _.mixin(Dataset.prototype, EventEmitter, {
-            _overwrite: function overwrite(query, suggestions) {
-                suggestions = suggestions || [];
-                if (suggestions.length) {
-                    this._renderSuggestions(query, suggestions);
-                } else if (this.async && this.templates.pending) {
-                    this._renderPending(query);
-                } else if (!this.async && this.templates.notFound) {
-                    this._renderNotFound(query);
-                } else {
-                    this._empty();
-                }
-                this.trigger("rendered", this.name, suggestions, false);
-            },
-            _append: function append(query, suggestions) {
-                suggestions = suggestions || [];
-                if (suggestions.length && this.$lastSuggestion.length) {
-                    this._appendSuggestions(query, suggestions);
-                } else if (suggestions.length) {
-                    this._renderSuggestions(query, suggestions);
-                } else if (!this.$lastSuggestion.length && this.templates.notFound) {
-                    this._renderNotFound(query);
-                }
-                this.trigger("rendered", this.name, suggestions, true);
-            },
-            _renderSuggestions: function renderSuggestions(query, suggestions) {
-                var $fragment;
-                $fragment = this._getSuggestionsFragment(query, suggestions);
-                this.$lastSuggestion = $fragment.children().last();
-                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
-            },
-            _appendSuggestions: function appendSuggestions(query, suggestions) {
-                var $fragment, $lastSuggestion;
-                $fragment = this._getSuggestionsFragment(query, suggestions);
-                $lastSuggestion = $fragment.children().last();
-                this.$lastSuggestion.after($fragment);
-                this.$lastSuggestion = $lastSuggestion;
-            },
-            _renderPending: function renderPending(query) {
-                var template = this.templates.pending;
-                this._resetLastSuggestion();
-                template && this.$el.html(template({
-                    query: query,
-                    dataset: this.name
-                }));
-            },
-            _renderNotFound: function renderNotFound(query) {
-                var template = this.templates.notFound;
-                this._resetLastSuggestion();
-                template && this.$el.html(template({
-                    query: query,
-                    dataset: this.name
-                }));
-            },
-            _empty: function empty() {
-                this.$el.empty();
-                this._resetLastSuggestion();
-            },
-            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
-                var that = this, fragment;
-                fragment = document.createDocumentFragment();
-                _.each(suggestions, function getSuggestionNode(suggestion) {
-                    var $el, context;
-                    context = that._injectQuery(query, suggestion);
-                    $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
-                    fragment.appendChild($el[0]);
-                });
-                this.highlight && highlight({
-                    className: this.classes.highlight,
-                    node: fragment,
-                    pattern: query
-                });
-                return $(fragment);
-            },
-            _getFooter: function getFooter(query, suggestions) {
-                return this.templates.footer ? this.templates.footer({
-                    query: query,
-                    suggestions: suggestions,
-                    dataset: this.name
-                }) : null;
-            },
-            _getHeader: function getHeader(query, suggestions) {
-                return this.templates.header ? this.templates.header({
-                    query: query,
-                    suggestions: suggestions,
-                    dataset: this.name
-                }) : null;
-            },
-            _resetLastSuggestion: function resetLastSuggestion() {
-                this.$lastSuggestion = $();
-            },
-            _injectQuery: function injectQuery(query, obj) {
-                return _.isObject(obj) ? _.mixin({
-                    _query: query
-                }, obj) : obj;
-            },
-            update: function update(query) {
-                var that = this, canceled = false, syncCalled = false, rendered = 0;
-                this.cancel();
-                this.cancel = function cancel() {
-                    canceled = true;
-                    that.cancel = $.noop;
-                    that.async && that.trigger("asyncCanceled", query);
-                };
-                this.source(query, sync, async);
-                !syncCalled && sync([]);
-                function sync(suggestions) {
-                    if (syncCalled) {
-                        return;
-                    }
-                    syncCalled = true;
-                    suggestions = (suggestions || []).slice(0, that.limit);
-                    rendered = suggestions.length;
-                    that._overwrite(query, suggestions);
-                    if (rendered < that.limit && that.async) {
-                        that.trigger("asyncRequested", query);
-                    }
-                }
-                function async(suggestions) {
-                    suggestions = suggestions || [];
-                    if (!canceled && rendered < that.limit) {
-                        that.cancel = $.noop;
-                        rendered += suggestions.length;
-                        that._append(query, suggestions.slice(0, that.limit - rendered));
-                        that.async && that.trigger("asyncReceived", query);
-                    }
-                }
-            },
-            cancel: $.noop,
-            clear: function clear() {
-                this._empty();
-                this.cancel();
-                this.trigger("cleared");
-            },
-            isEmpty: function isEmpty() {
-                return this.$el.is(":empty");
-            },
-            destroy: function destroy() {
-                this.$el = $("<div>");
-            }
-        });
-        return Dataset;
-        function getDisplayFn(display) {
-            display = display || _.stringify;
-            return _.isFunction(display) ? display : displayFn;
-            function displayFn(obj) {
-                return obj[display];
-            }
-        }
-        function getTemplates(templates, displayFn) {
-            return {
-                notFound: templates.notFound && _.templatify(templates.notFound),
-                pending: templates.pending && _.templatify(templates.pending),
-                header: templates.header && _.templatify(templates.header),
-                footer: templates.footer && _.templatify(templates.footer),
-                suggestion: templates.suggestion || suggestionTemplate
-            };
-            function suggestionTemplate(context) {
-                return $("<div>").text(displayFn(context));
-            }
-        }
-        function isValidName(str) {
-            return /^[_a-zA-Z0-9-]+$/.test(str);
-        }
-    }();
-    var Menu = function() {
-        "use strict";
-        function Menu(o, www) {
-            var that = this;
-            o = o || {};
-            if (!o.node) {
-                $.error("node is required");
-            }
-            www.mixin(this);
-            this.$node = $(o.node);
-            this.query = null;
-            this.datasets = _.map(o.datasets, initializeDataset);
-            function initializeDataset(oDataset) {
-                var node = that.$node.find(oDataset.node).first();
-                oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
-                return new Dataset(oDataset, www);
-            }
-        }
-        _.mixin(Menu.prototype, EventEmitter, {
-            _onSelectableClick: function onSelectableClick($e) {
-                this.trigger("selectableClicked", $($e.currentTarget));
-            },
-            _onRendered: function onRendered(type, dataset, suggestions, async) {
-                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-                this.trigger("datasetRendered", dataset, suggestions, async);
-            },
-            _onCleared: function onCleared() {
-                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-                this.trigger("datasetCleared");
-            },
-            _propagate: function propagate() {
-                this.trigger.apply(this, arguments);
-            },
-            _allDatasetsEmpty: function allDatasetsEmpty() {
-                return _.every(this.datasets, isDatasetEmpty);
-                function isDatasetEmpty(dataset) {
-                    return dataset.isEmpty();
-                }
-            },
-            _getSelectables: function getSelectables() {
-                return this.$node.find(this.selectors.selectable);
-            },
-            _removeCursor: function _removeCursor() {
-                var $selectable = this.getActiveSelectable();
-                $selectable && $selectable.removeClass(this.classes.cursor);
-            },
-            _ensureVisible: function ensureVisible($el) {
-                var elTop, elBottom, nodeScrollTop, nodeHeight;
-                elTop = $el.position().top;
-                elBottom = elTop + $el.outerHeight(true);
-                nodeScrollTop = this.$node.scrollTop();
-                nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
-                if (elTop < 0) {
-                    this.$node.scrollTop(nodeScrollTop + elTop);
-                } else if (nodeHeight < elBottom) {
-                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
-                }
-            },
-            bind: function() {
-                var that = this, onSelectableClick;
-                onSelectableClick = _.bind(this._onSelectableClick, this);
-                this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
-                _.each(this.datasets, function(dataset) {
-                    dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
-                });
-                return this;
-            },
-            isOpen: function isOpen() {
-                return this.$node.hasClass(this.classes.open);
-            },
-            open: function open() {
-                this.$node.addClass(this.classes.open);
-            },
-            close: function close() {
-                this.$node.removeClass(this.classes.open);
-                this._removeCursor();
-            },
-            setLanguageDirection: function setLanguageDirection(dir) {
-                this.$node.attr("dir", dir);
-            },
-            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
-                var $selectables, $oldCursor, oldIndex, newIndex;
-                $oldCursor = this.getActiveSelectable();
-                $selectables = this._getSelectables();
-                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
-                newIndex = oldIndex + delta;
-                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
-                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
-                return newIndex === -1 ? null : $selectables.eq(newIndex);
-            },
-            setCursor: function setCursor($selectable) {
-                this._removeCursor();
-                if ($selectable = $selectable && $selectable.first()) {
-                    $selectable.addClass(this.classes.cursor);
-                    this._ensureVisible($selectable);
-                }
-            },
-            getSelectableData: function getSelectableData($el) {
-                return $el && $el.length ? Dataset.extractData($el) : null;
-            },
-            getActiveSelectable: function getActiveSelectable() {
-                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
-                return $selectable.length ? $selectable : null;
-            },
-            getTopSelectable: function getTopSelectable() {
-                var $selectable = this._getSelectables().first();
-                return $selectable.length ? $selectable : null;
-            },
-            update: function update(query) {
-                var isValidUpdate = query !== this.query;
-                if (isValidUpdate) {
-                    this.query = query;
-                    _.each(this.datasets, updateDataset);
-                }
-                return isValidUpdate;
-                function updateDataset(dataset) {
-                    dataset.update(query);
-                }
-            },
-            empty: function empty() {
-                _.each(this.datasets, clearDataset);
-                this.query = null;
-                this.$node.addClass(this.classes.empty);
-                function clearDataset(dataset) {
-                    dataset.clear();
-                }
-            },
-            destroy: function destroy() {
-                this.$node.off(".tt");
-                this.$node = $("<div>");
-                _.each(this.datasets, destroyDataset);
-                function destroyDataset(dataset) {
-                    dataset.destroy();
-                }
-            }
-        });
-        return Menu;
-    }();
-    var DefaultMenu = function() {
-        "use strict";
-        var s = Menu.prototype;
-        function DefaultMenu() {
-            Menu.apply(this, [].slice.call(arguments, 0));
-        }
-        _.mixin(DefaultMenu.prototype, Menu.prototype, {
-            open: function open() {
-                !this._allDatasetsEmpty() && this._show();
-                return s.open.apply(this, [].slice.call(arguments, 0));
-            },
-            close: function close() {
-                this._hide();
-                return s.close.apply(this, [].slice.call(arguments, 0));
-            },
-            _onRendered: function onRendered() {
-                if (this._allDatasetsEmpty()) {
-                    this._hide();
-                } else {
-                    this.isOpen() && this._show();
-                }
-                return s._onRendered.apply(this, [].slice.call(arguments, 0));
-            },
-            _onCleared: function onCleared() {
-                if (this._allDatasetsEmpty()) {
-                    this._hide();
-                } else {
-                    this.isOpen() && this._show();
-                }
-                return s._onCleared.apply(this, [].slice.call(arguments, 0));
-            },
-            setLanguageDirection: function setLanguageDirection(dir) {
-                this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
-                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
-            },
-            _hide: function hide() {
-                this.$node.hide();
-            },
-            _show: function show() {
-                this.$node.css("display", "block");
-            }
-        });
-        return DefaultMenu;
-    }();
-    var Typeahead = function() {
-        "use strict";
-        function Typeahead(o, www) {
-            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
-            o = o || {};
-            if (!o.input) {
-                $.error("missing input");
-            }
-            if (!o.menu) {
-                $.error("missing menu");
-            }
-            if (!o.eventBus) {
-                $.error("missing event bus");
-            }
-            www.mixin(this);
-            this.eventBus = o.eventBus;
-            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
-            this.input = o.input;
-            this.menu = o.menu;
-            this.enabled = true;
-            this.active = false;
-            this.input.hasFocus() && this.activate();
-            this.dir = this.input.getLangDir();
-            this._hacks();
-            this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
-            onFocused = c(this, "activate", "open", "_onFocused");
-            onBlurred = c(this, "deactivate", "_onBlurred");
-            onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
-            onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
-            onEscKeyed = c(this, "isActive", "_onEscKeyed");
-            onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
-            onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
-            onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
-            onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
-            onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
-            onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
-            this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
-        }
-        _.mixin(Typeahead.prototype, {
-            _hacks: function hacks() {
-                var $input, $menu;
-                $input = this.input.$input || $("<div>");
-                $menu = this.menu.$node || $("<div>");
-                $input.on("blur.tt", function($e) {
-                    var active, isActive, hasActive;
-                    active = document.activeElement;
-                    isActive = $menu.is(active);
-                    hasActive = $menu.has(active).length > 0;
-                    if (_.isMsie() && (isActive || hasActive)) {
-                        $e.preventDefault();
-                        $e.stopImmediatePropagation();
-                        _.defer(function() {
-                            $input.focus();
-                        });
-                    }
-                });
-                $menu.on("mousedown.tt", function($e) {
-                    $e.preventDefault();
-                });
-            },
-            _onSelectableClicked: function onSelectableClicked(type, $el) {
-                this.select($el);
-            },
-            _onDatasetCleared: function onDatasetCleared() {
-                this._updateHint();
-            },
-            _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
-                this._updateHint();
-                this.eventBus.trigger("render", suggestions, async, dataset);
-            },
-            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
-                this.eventBus.trigger("asyncrequest", query, dataset);
-            },
-            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
-                this.eventBus.trigger("asynccancel", query, dataset);
-            },
-            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
-                this.eventBus.trigger("asyncreceive", query, dataset);
-            },
-            _onFocused: function onFocused() {
-                this._minLengthMet() && this.menu.update(this.input.getQuery());
-            },
-            _onBlurred: function onBlurred() {
-                if (this.input.hasQueryChangedSinceLastFocus()) {
-                    this.eventBus.trigger("change", this.input.getQuery());
-                }
-            },
-            _onEnterKeyed: function onEnterKeyed(type, $e) {
-                var $selectable;
-                if ($selectable = this.menu.getActiveSelectable()) {
-                    this.select($selectable) && $e.preventDefault();
-                }
-            },
-            _onTabKeyed: function onTabKeyed(type, $e) {
-                var $selectable;
-                if ($selectable = this.menu.getActiveSelectable()) {
-                    this.select($selectable) && $e.preventDefault();
-                } else if ($selectable = this.menu.getTopSelectable()) {
-                    this.autocomplete($selectable) && $e.preventDefault();
-                }
-            },
-            _onEscKeyed: function onEscKeyed() {
-                this.close();
-            },
-            _onUpKeyed: function onUpKeyed() {
-                this.moveCursor(-1);
-            },
-            _onDownKeyed: function onDownKeyed() {
-                this.moveCursor(+1);
-            },
-            _onLeftKeyed: function onLeftKeyed() {
-                if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
-                    this.autocomplete(this.menu.getTopSelectable());
-                }
-            },
-            _onRightKeyed: function onRightKeyed() {
-                if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
-                    this.autocomplete(this.menu.getTopSelectable());
-                }
-            },
-            _onQueryChanged: function onQueryChanged(e, query) {
-                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
-            },
-            _onWhitespaceChanged: function onWhitespaceChanged() {
-                this._updateHint();
-            },
-            _onLangDirChanged: function onLangDirChanged(e, dir) {
-                if (this.dir !== dir) {
-                    this.dir = dir;
-                    this.menu.setLanguageDirection(dir);
-                }
-            },
-            _openIfActive: function openIfActive() {
-                this.isActive() && this.open();
-            },
-            _minLengthMet: function minLengthMet(query) {
-                query = _.isString(query) ? query : this.input.getQuery() || "";
-                return query.length >= this.minLength;
-            },
-            _updateHint: function updateHint() {
-                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
-                $selectable = this.menu.getTopSelectable();
-                data = this.menu.getSelectableData($selectable);
-                val = this.input.getInputValue();
-                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
-                    query = Input.normalizeQuery(val);
-                    escapedQuery = _.escapeRegExChars(query);
-                    frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
-                    match = frontMatchRegEx.exec(data.val);
-                    match && this.input.setHint(val + match[1]);
-                } else {
-                    this.input.clearHint();
-                }
-            },
-            isEnabled: function isEnabled() {
-                return this.enabled;
-            },
-            enable: function enable() {
-                this.enabled = true;
-            },
-            disable: function disable() {
-                this.enabled = false;
-            },
-            isActive: function isActive() {
-                return this.active;
-            },
-            activate: function activate() {
-                if (this.isActive()) {
-                    return true;
-                } else if (!this.isEnabled() || this.eventBus.before("active")) {
-                    return false;
-                } else {
-                    this.active = true;
-                    this.eventBus.trigger("active");
-                    return true;
-                }
-            },
-            deactivate: function deactivate() {
-                if (!this.isActive()) {
-                    return true;
-                } else if (this.eventBus.before("idle")) {
-                    return false;
-                } else {
-                    this.active = false;
-                    this.close();
-                    this.eventBus.trigger("idle");
-                    return true;
-                }
-            },
-            isOpen: function isOpen() {
-                return this.menu.isOpen();
-            },
-            open: function open() {
-                if (!this.isOpen() && !this.eventBus.before("open")) {
-                    this.menu.open();
-                    this._updateHint();
-                    this.eventBus.trigger("open");
-                }
-                return this.isOpen();
-            },
-            close: function close() {
-                if (this.isOpen() && !this.eventBus.before("close")) {
-                    this.menu.close();
-                    this.input.clearHint();
-                    this.input.resetInputValue();
-                    this.eventBus.trigger("close");
-                }
-                return !this.isOpen();
-            },
-            setVal: function setVal(val) {
-                this.input.setQuery(_.toStr(val));
-            },
-            getVal: function getVal() {
-                return this.input.getQuery();
-            },
-            select: function select($selectable) {
-                var data = this.menu.getSelectableData($selectable);
-                if (data && !this.eventBus.before("select", data.obj)) {
-                    this.input.setQuery(data.val, true);
-                    this.eventBus.trigger("select", data.obj);
-                    this.close();
-                    return true;
-                }
-                return false;
-            },
-            autocomplete: function autocomplete($selectable) {
-                var query, data, isValid;
-                query = this.input.getQuery();
-                data = this.menu.getSelectableData($selectable);
-                isValid = data && query !== data.val;
-                if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
-                    this.input.setQuery(data.val);
-                    this.eventBus.trigger("autocomplete", data.obj);
-                    return true;
-                }
-                return false;
-            },
-            moveCursor: function moveCursor(delta) {
-                var query, $candidate, data, payload, cancelMove;
-                query = this.input.getQuery();
-                $candidate = this.menu.selectableRelativeToCursor(delta);
-                data = this.menu.getSelectableData($candidate);
-                payload = data ? data.obj : null;
-                cancelMove = this._minLengthMet() && this.menu.update(query);
-                if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
-                    this.menu.setCursor($candidate);
-                    if (data) {
-                        this.input.setInputValue(data.val);
-                    } else {
-                        this.input.resetInputValue();
-                        this._updateHint();
-                    }
-                    this.eventBus.trigger("cursorchange", payload);
-                    return true;
-                }
-                return false;
-            },
-            destroy: function destroy() {
-                this.input.destroy();
-                this.menu.destroy();
-            }
-        });
-        return Typeahead;
-        function c(ctx) {
-            var methods = [].slice.call(arguments, 1);
-            return function() {
-                var args = [].slice.call(arguments);
-                _.each(methods, function(method) {
-                    return ctx[method].apply(ctx, args);
-                });
-            };
-        }
-    }();
-    (function() {
-        "use strict";
-        var old, keys, methods;
-        old = $.fn.typeahead;
-        keys = {
-            www: "tt-www",
-            attrs: "tt-attrs",
-            typeahead: "tt-typeahead"
-        };
-        methods = {
-            initialize: function initialize(o, datasets) {
-                var www;
-                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
-                o = o || {};
-                www = WWW(o.classNames);
-                return this.each(attach);
-                function attach() {
-                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;
-                    _.each(datasets, function(d) {
-                        d.highlight = !!o.highlight;
-                    });
-                    $input = $(this);
-                    $wrapper = $(www.html.wrapper);
-                    $hint = $elOrNull(o.hint);
-                    $menu = $elOrNull(o.menu);
-                    defaultHint = o.hint !== false && !$hint;
-                    defaultMenu = o.menu !== false && !$menu;
-                    defaultHint && ($hint = buildHintFromInput($input, www));
-                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
-                    $hint && $hint.val("");
-                    $input = prepInput($input, www);
-                    if (defaultHint || defaultMenu) {
-                        $wrapper.css(www.css.wrapper);
-                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
-                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
-                    }
-                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;
-                    eventBus = new EventBus({
-                        el: $input
-                    });
-                    input = new Input({
-                        hint: $hint,
-                        input: $input
-                    }, www);
-                    menu = new MenuConstructor({
-                        node: $menu,
-                        datasets: datasets
-                    }, www);
-                    typeahead = new Typeahead({
-                        input: input,
-                        menu: menu,
-                        eventBus: eventBus,
-                        minLength: o.minLength
-                    }, www);
-                    $input.data(keys.www, www);
-                    $input.data(keys.typeahead, typeahead);
-                }
-            },
-            isEnabled: function isEnabled() {
-                var enabled;
-                ttEach(this.first(), function(t) {
-                    enabled = t.isEnabled();
-                });
-                return enabled;
-            },
-            enable: function enable() {
-                ttEach(this, function(t) {
-                    t.enable();
-                });
-                return this;
-            },
-            disable: function disable() {
-                ttEach(this, function(t) {
-                    t.disable();
-                });
-                return this;
-            },
-            isActive: function isActive() {
-                var active;
-                ttEach(this.first(), function(t) {
-                    active = t.isActive();
-                });
-                return active;
-            },
-            activate: function activate() {
-                ttEach(this, function(t) {
-                    t.activate();
-                });
-                return this;
-            },
-            deactivate: function deactivate() {
-                ttEach(this, function(t) {
-                    t.deactivate();
-                });
-                return this;
-            },
-            isOpen: function isOpen() {
-                var open;
-                ttEach(this.first(), function(t) {
-                    open = t.isOpen();
-                });
-                return open;
-            },
-            open: function open() {
-                ttEach(this, function(t) {
-                    t.open();
-                });
-                return this;
-            },
-            close: function close() {
-                ttEach(this, function(t) {
-                    t.close();
-                });
-                return this;
-            },
-            select: function select(el) {
-                var success = false, $el = $(el);
-                ttEach(this.first(), function(t) {
-                    success = t.select($el);
-                });
-                return success;
-            },
-            autocomplete: function autocomplete(el) {
-                var success = false, $el = $(el);
-                ttEach(this.first(), function(t) {
-                    success = t.autocomplete($el);
-                });
-                return success;
-            },
-            moveCursor: function moveCursoe(delta) {
-                var success = false;
-                ttEach(this.first(), function(t) {
-                    success = t.moveCursor(delta);
-                });
-                return success;
-            },
-            val: function val(newVal) {
-                var query;
-                if (!arguments.length) {
-                    ttEach(this.first(), function(t) {
-                        query = t.getVal();
-                    });
-                    return query;
-                } else {
-                    ttEach(this, function(t) {
-                        t.setVal(newVal);
-                    });
-                    return this;
-                }
-            },
-            destroy: function destroy() {
-                ttEach(this, function(typeahead, $input) {
-                    revert($input);
-                    typeahead.destroy();
-                });
-                return this;
-            }
-        };
-        $.fn.typeahead = function(method) {
-            if (methods[method]) {
-                return methods[method].apply(this, [].slice.call(arguments, 1));
-            } else {
-                return methods.initialize.apply(this, arguments);
-            }
-        };
-        $.fn.typeahead.noConflict = function noConflict() {
-            $.fn.typeahead = old;
-            return this;
-        };
-        function ttEach($els, fn) {
-            $els.each(function() {
-                var $input = $(this), typeahead;
-                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
-            });
-        }
-        function buildHintFromInput($input, www) {
-            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
-                autocomplete: "off",
-                spellcheck: "false",
-                tabindex: -1
-            });
-        }
-        function prepInput($input, www) {
-            $input.data(keys.attrs, {
-                dir: $input.attr("dir"),
-                autocomplete: $input.attr("autocomplete"),
-                spellcheck: $input.attr("spellcheck"),
-                style: $input.attr("style")
-            });
-            $input.addClass(www.classes.input).attr({
-                autocomplete: "off",
-                spellcheck: false
-            });
-            try {
-                !$input.attr("dir") && $input.attr("dir", "auto");
-            } catch (e) {}
-            return $input;
-        }
-        function getBackgroundStyles($el) {
-            return {
-                backgroundAttachment: $el.css("background-attachment"),
-                backgroundClip: $el.css("background-clip"),
-                backgroundColor: $el.css("background-color"),
-                backgroundImage: $el.css("background-image"),
-                backgroundOrigin: $el.css("background-origin"),
-                backgroundPosition: $el.css("background-position"),
-                backgroundRepeat: $el.css("background-repeat"),
-                backgroundSize: $el.css("background-size")
-            };
-        }
-        function revert($input) {
-            var www, $wrapper;
-            www = $input.data(keys.www);
-            $wrapper = $input.parent().filter(www.selectors.wrapper);
-            _.each($input.data(keys.attrs), function(val, key) {
-                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
-            });
-            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
-            if ($wrapper.length) {
-                $input.detach().insertAfter($wrapper);
-                $wrapper.remove();
-            }
-        }
-        function $elOrNull(obj) {
-            var isValid, $el;
-            isValid = _.isJQuery(obj) || _.isElement(obj);
-            $el = isValid ? $(obj).first() : [];
-            return $el.length ? $el : null;
-        }
-    })();
-});

Разлика између датотеке није приказан због своје велике величине
+ 0 - 6
vendor/bower-asset/typeahead.js/dist/typeahead.jquery.min.js


+ 0 - 277
vendor/bower-asset/typeahead.js/doc/bloodhound.md

@@ -1,277 +0,0 @@
-Bloodhound
-==========
-
-Bloodhound is the typeahead.js suggestion engine. Bloodhound is robust, 
-flexible, and offers advanced functionalities such as prefetching, intelligent
-caching, fast lookups, and backfilling with remote data.
-
-Table of Contents
------------------
-
-* [Features](#features)
-* [Usage](#usage)
-  * [API](#api)
-  * [Options](#options)
-  * [Prefetch](#prefetch)
-  * [Remote](#remote)
-
-Features
---------
-
-* Works with hardcoded data
-* Prefetches data on initialization to reduce suggestion latency
-* Uses local storage intelligently to cut down on network requests
-* Backfills suggestions from a remote source
-* Rate-limits and caches network requests to remote sources to lighten the load
-
-Usage
------
-
-### API
-
-* [`new Bloodhound(options)`](#new-bloodhoundoptions)
-* [`Bloodhound.noConflict()`](#bloodhoundnoconflict)
-* [`Bloodhound#initialize(reinitialize)`](#bloodhoundinitializereinitialize)
-* [`Bloodhound#add(data)`](#bloodhoundadddata)
-* [`Bloodhound#get(ids)`](#bloodhoundgetids)
-* [`Bloodhound#search(query, sync, async)`](#bloodhoundsearchquery-sync-async)
-* [`Bloodhound#clear()`](#bloodhoundclear)
-
-#### new Bloodhound(options)
-
-The constructor function. It takes an [options hash](#options) as its only 
-argument.
-
-```javascript
-var engine = new Bloodhound({
-  local: ['dog', 'pig', 'moose'],
-  queryTokenizer: Bloodhound.tokenizers.whitespace,
-  datumTokenizer: Bloodhound.tokenizers.whitespace
-});
-```
-
-#### Bloodhound.noConflict()
-
-Returns a reference to `Bloodhound` and reverts `window.Bloodhound` to its 
-previous value. Can be used to avoid naming collisions. 
-
-```javascript
-var Dachshund = Bloodhound.noConflict();
-```
-
-#### Bloodhound#initialize(reinitialize) 
-
-Kicks off the initialization of the suggestion engine. Initialization entails
-adding the data provided by `local` and `prefetch` to the internal search 
-index as well as setting up transport mechanism used by `remote`. Before 
-`#initialize` is called, the `#get` and `#search` methods will effectively be
-no-ops.
-
-Note, unless the `initialize` option is `false`, this method is implicitly
-called by the constructor.
-
-```javascript
-var engine = new Bloodhound({
-  initialize: false,
-  local: ['dog', 'pig', 'moose'],
-  queryTokenizer: Bloodhound.tokenizers.whitespace,
-  datumTokenizer: Bloodhound.tokenizers.whitespace
-});
-
-var promise = engine.initialize();
-
-promise
-.done(function() { console.log('ready to go!'); })
-.fail(function() { console.log('err, something went wrong :('); });
-```
-
-After initialization, how subsequent invocations of `#initialize` behave 
-depends on the `reinitialize` argument. If `reinitialize` is falsy, the
-method will not execute the initialization logic and will just return the same 
-jQuery promise returned by the initial invocation. If `reinitialize` is truthy,
-the method will behave as if it were being called for the first time.
-
-```javascript
-var promise1 = engine.initialize();
-var promise2 = engine.initialize();
-var promise3 = engine.initialize(true);
-
-assert(promise1 === promise2);
-assert(promise3 !== promise1 && promise3 !== promise2);
-```
-
-<!-- section links -->
-
-[jQuery promise]: http://api.jquery.com/Types/#Promise
-
-#### Bloodhound#add(data)
-
-Takes one argument, `data`, which is expected to be an array. The data passed
-in will get added to the internal search index.
-
-```javascript
-engine.add([{ val: 'one' }, { val: 'two' }]);
-```
-
-#### Bloodhound#get(ids)
-
-Returns the data in the local search index corresponding to `ids`.
-
-```javascript
-  var engine = new Bloodhound({
-    local: [{ id: 1, name: 'dog' }, { id: 2, name: 'pig' }],
-    identify: function(obj) { return obj.id; },
-    queryTokenizer: Bloodhound.tokenizers.whitespace,
-    datumTokenizer: Bloodhound.tokenizers.whitespace
-  });
-
-  engine.get([1, 3]); // [{ id: 1, name: 'dog' }, null]
-```
-
-#### Bloodhound#search(query, sync, async)
-
-Returns the data that matches `query`. Matches found in the local search index
-will be passed to the `sync` callback. If the data passed to `sync` doesn't 
-contain at least `sufficient` number of datums, `remote` data will be requested 
-and then passed to the `async` callback.
-
-```javascript
-bloodhound.get(myQuery, sync, async);
-
-function sync(datums) {
-  console.log('datums from `local`, `prefetch`, and `#add`');
-  console.log(datums);
-}
-
-function async(datums) {
-  console.log('datums from `remote`');
-  console.log(datums);
-}
-```
-
-#### Bloodhound#clear()
-
-Clears the internal search index that's powered by `local`, `prefetch`, and 
-`#add`.
-
-```javascript
-engine.clear();
-```
-
-### Options
-
-When instantiating a Bloodhound suggestion engine, there are a number of 
-options you can configure.
-
-* `datumTokenizer` – A function with the signature `(datum)` that transforms a
-  datum into an array of string tokens. **Required**.
-
-* `queryTokenizer` – A function with the signature `(query)` that transforms a
-  query into an array of string tokens. **Required**.
-
-* `initialize` – If set to `false`, the Bloodhound instance will not be 
-  implicitly initialized by the constructor function. Defaults to `true`.
-
-* `identify` – Given a datum, this function is expected to return a unique id
-  for it. Defaults to `JSON.stringify`. Note that it is **highly recommended**
-  to override this option.
-
-* `sufficient` – If the number of datums provided from the internal search 
-  index is less than `sufficient`, `remote` will be used to backfill search
-  requests triggered by calling `#search`. Defaults to `5`.
-
-* `sorter` – A [compare function] used to sort data returned from the internal
-  search index.
-
-* `local` – An array of data or a function that returns an array of data. The 
-  data will be added to the internal search index when `#initialize` is called.
-
-* `prefetch` – Can be a URL to a JSON file containing an array of data or, if 
-  more configurability is needed, a [prefetch options hash](#prefetch).
-
-* `remote` – Can be a URL to fetch data from when the data provided by 
-  the internal search index is insufficient or, if more configurability is 
-  needed, a [remote options hash](#remote).
-
-<!-- section links -->
-
-[compare function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
-
-### Prefetch
-
-Prefetched data is fetched and processed on initialization. If the browser 
-supports local storage, the processed data will be cached there to 
-prevent additional network requests on subsequent page loads.
-
-**WARNING:** While it's possible to get away with it for smaller data sets, 
-prefetched data isn't meant to contain entire sets of data. Rather, it should 
-act as a first-level cache. Ignoring this warning means you'll run the risk of 
-hitting [local storage limits].
-
-When configuring `prefetch`, the following options are available.
-
-* `url` – The URL prefetch data should be loaded from. **Required.**
-
-* `cache` – If `false`, will not attempt to read or write to local storage and
-  will always load prefetch data from `url` on initialization.  Defaults to 
-  `true`.
-
-* `ttl` – The time (in milliseconds) the prefetched data should be cached in 
-  local storage. Defaults to `86400000` (1 day).
-
-* `cacheKey` – The key that data will be stored in local storage under. 
-  Defaults to value of `url`.
-
-* `thumbprint` – A string used for thumbprinting prefetched data. If this
-  doesn't match what's stored in local storage, the data will be refetched.
-
-* `prepare` – A function that provides a hook to allow you to prepare the 
-  settings object passed to `transport` when a request is about to be made. 
-  The function signature should be `prepare(settings)` where `settings` is the 
-  default settings object created internally by the Bloodhound instance. The 
-  `prepare` function should return a settings object. Defaults to the 
-  [identity function].
-
-* `transform` – A function with the signature `transform(response)` that allows
-  you to transform the prefetch response before the Bloodhound instance operates 
-  on it. Defaults to the [identity function].
-
-<!-- section links -->
-
-[local storage limits]: http://stackoverflow.com/a/2989317
-[identity function]: http://en.wikipedia.org/wiki/Identity_function
-
-### Remote
-
-Bloodhound only goes to the network when the internal search engine cannot 
-provide a sufficient number of results. In order to prevent an obscene number 
-of requests being made to the remote endpoint, requests are rate-limited.
-
-When configuring `remote`, the following options are available.
-
-* `url` – The URL remote data should be loaded from. **Required.**
-
-* `prepare` – A function that provides a hook to allow you to prepare the 
-  settings object passed to `transport` when a request is about to be made. 
-  The function signature should be `prepare(query, settings)`, where `query` is
-  the query `#search` was called with and `settings` is the default settings
-  object created internally by the Bloodhound instance. The `prepare` function
-  should return a settings object. Defaults to the [identity function].
-
-* `wildcard` – A convenience option for `prepare`. If set, `prepare` will be a
-  function that replaces the value of this option in `url` with the URI encoded
-  query.
-
-* `rateLimitBy` – The method used to rate-limit network requests. Can be either 
-  `debounce` or `throttle`. Defaults to `debounce`.
-
-* `rateLimitWait` – The time interval in milliseconds that will be used by 
-  `rateLimitBy`. Defaults to `300`.
-
-* `transform` – A function with the signature `transform(response)` that allows
-  you to transform the remote response before the Bloodhound instance operates 
-  on it. Defaults to the [identity function].
-
-<!-- section links -->
-
-[identity function]: http://en.wikipedia.org/wiki/Identity_function

+ 0 - 288
vendor/bower-asset/typeahead.js/doc/jquery_typeahead.md

@@ -1,288 +0,0 @@
-jQuery#typeahead
-----------------
-
-The UI component of typeahead.js is available as a jQuery plugin. It's 
-responsible for rendering suggestions and handling DOM interactions.
-
-Table of Contents
------------------
-
-* [Features](#features)
-* [Usage](#usage)
-  * [API](#api)
-  * [Options](#options)
-  * [Datasets](#datasets)
-  * [Custom Events](#custom-events)
-  * [Class Names](#class-names)
-
-Features
---------
-
-* Displays suggestions to end-users as they type
-* Shows top suggestion as a hint (i.e. background text)
-* Supports custom templates to allow for UI flexibility
-* Works well with RTL languages and input method editors
-* Highlights query matches within the suggestion
-* Triggers custom events to encourage extensibility
-
-Usage
------
-
-### API
-
-* [`jQuery#typeahead(options, [*datasets])`](#jquerytypeaheadoptions-datasets)
-* [`jQuery#typeahead('val')`](#jquerytypeaheadval)
-* [`jQuery#typeahead('val', val)`](#jquerytypeaheadval-val)
-* [`jQuery#typeahead('destroy')`](#jquerytypeaheaddestroy)
-* [`jQuery.fn.typeahead.noConflict()`](#jqueryfntypeaheadnoconflict)
-
-#### jQuery#typeahead(options, [\*datasets])
-
-For a given `input[type="text"]`, enables typeahead functionality. `options` 
-is an options hash that's used for configuration. Refer to [Options](#options) 
-for more info regarding the available configs. Subsequent arguments 
-(`*datasets`), are individual option hashes for datasets. For more details 
-regarding datasets, refer to [Datasets](#datasets).
-
-```javascript
-$('.typeahead').typeahead({
-  minLength: 3,
-  highlight: true
-},
-{
-  name: 'my-dataset',
-  source: mySource
-});
-```
-
-#### jQuery#typeahead('val')
-
-Returns the current value of the typeahead. The value is the text the user has 
-entered into the `input` element.
-
-```javascript
-var myVal = $('.typeahead').typeahead('val');
-```
-
-#### jQuery#typeahead('val', val)
-
-Sets the value of the typeahead. This should be used in place of `jQuery#val`.
-
-```javascript
-$('.typeahead').typeahead('val', myVal);
-```
-
-#### jQuery#typeahead('open')
-
-Opens the suggestion menu.
-
-```javascript
-$('.typeahead').typeahead('open');
-```
-
-#### jQuery#typeahead('close')
-
-Closes the suggestion menu.
-
-```javascript
-$('.typeahead').typeahead('close');
-```
-
-#### jQuery#typeahead('destroy')
-
-Removes typeahead functionality and reverts the `input` element back to its 
-original state.
-
-```javascript
-$('.typeahead').typeahead('destroy');
-```
-
-#### jQuery.fn.typeahead.noConflict()
-
-Returns a reference to the typeahead plugin and reverts `jQuery.fn.typeahead` 
-to its previous value. Can be used to avoid naming collisions. 
-
-```javascript
-var typeahead = jQuery.fn.typeahead.noConflict();
-jQuery.fn._typeahead = typeahead;
-```
-
-### Options
-
-When initializing a typeahead, there are a number of options you can configure.
-
-* `highlight` – If `true`, when suggestions are rendered, pattern matches
-  for the current query in text nodes will be wrapped in a `strong` element with
-  its class set to `{{classNames.highlight}}`. Defaults to `false`.
-
-* `hint` – If `false`, the typeahead will not show a hint. Defaults to `true`.
-
-* `minLength` – The minimum character length needed before suggestions start 
-  getting rendered. Defaults to `1`.
-
-* `classNames` – For overriding the default class names used. See 
-  [Class Names](#class-names) for more details.
-
-### Datasets
-
-A typeahead is composed of one or more datasets. When an end-user modifies the
-value of a typeahead, each dataset will attempt to render suggestions for the
-new value. 
-
-For most use cases, one dataset should suffice. It's only in the scenario where
-you want rendered suggestions to be grouped based on some sort of categorical 
-relationship that you'd need to use multiple datasets. For example, on 
-twitter.com, the search typeahead groups results into recent searches, trends, 
-and accounts – that would be a great use case for using multiple datasets.
-
-Datasets can be configured using the following options.
-
-* `source` – The backing data source for suggestions. Expected to be a function 
-  with the signature `(query, syncResults, asyncResults)`. `syncResults` should
-  be called with suggestions computed synchronously and `asyncResults` should be 
-  called with suggestions computed asynchronously (e.g. suggestions that come 
-  for an AJAX request). `source` can also be a Bloodhound instance. 
-  **Required**.
-
-* `async` – Lets the dataset know if async suggestions should be expected. If
-  not set, this information is inferred from the signature of `source` i.e.
-  if the `source` function expects 3 arguments, `async` will be set to `true`.
-
-* `name` – The name of the dataset. This will be appended to 
-  `{{classNames.dataset}}-` to form the class name of the containing DOM 
-  element. Must only consist of underscores, dashes, letters (`a-z`), and 
-  numbers. Defaults to a random number.
-
-* `limit` – The max number of suggestions to be displayed. Defaults to `5`.
-
-* `display` – For a given suggestion, determines the string representation 
-  of it. This will be used when setting the value of the input control after a 
-  suggestion is selected. Can be either a key string or a function that 
-  transforms a suggestion object into a string. Defaults to stringifying the 
-  suggestion.
-
-* `templates` – A hash of templates to be used when rendering the dataset. Note
-  a precompiled template is a function that takes a JavaScript object as its
-  first argument and returns a HTML string.
-
-  * `notFound` – Rendered when `0` suggestions are available for the given 
-    query. Can be either a HTML string or a precompiled template. If it's a 
-    precompiled template, the passed in context will contain `query`.
-
-  * `pending` - Rendered when `0` synchronous suggestions are available but
-    asynchronous suggestions are expected. Can be either a HTML string or a 
-    precompiled template. If it's a precompiled template, the passed in context 
-    will contain `query`.
-
-  * `header`– Rendered at the top of the dataset when suggestions are present. 
-    Can be either a HTML string or a precompiled template. If it's a precompiled 
-    template, the passed in context will contain `query` and `suggestions`.
-
-  * `footer`– Rendered at the bottom of the dataset when suggestions are 
-    present. Can be either a HTML string or a precompiled template. If it's a 
-    precompiled template, the passed in context will contain `query` and
-    `suggestions`.
-
-  * `suggestion` – Used to render a single suggestion. If set, this has to be a 
-    precompiled template. The associated suggestion object will serve as the 
-    context. Defaults to the value of `display` wrapped in a `div` tag i.e. 
-    `<div>{{value}}</div>`.
-
-### Custom Events
-
-The following events get triggered on the input element during the life-cycle of
-a typeahead.
-
-* `typeahead:active` – Fired when the typeahead moves to active state.
-
-* `typeahead:idle` – Fired when the typeahead moves to idle state.
-
-* `typeahead:open` – Fired when the results container is opened.
-
-* `typeahead:close` – Fired when the results container is closed.
-
-* `typeahead:change` – Normalized version of the native [`change` event]. 
-  Fired when input loses focus and the value has changed since it originally 
-  received focus.
-
-* `typeahead:render` – Fired when suggestions are rendered for a dataset. The
-  event handler will be invoked with 4 arguments: the jQuery event object, the
-  suggestions that were rendered, a flag indicating whether the suggestions
-  were fetched asynchronously, and the name of the dataset the rendering 
-  occurred in.
-
-* `typeahead:select` – Fired when a suggestion is selected. The event handler 
-  will be invoked with 2 arguments: the jQuery event object and the suggestion
-  object that was selected.
-
-* `typeahead:autocomplete` – Fired when a autocompletion occurs. The 
-  event handler will be invoked with 2 arguments: the jQuery event object and 
-  the suggestion object that was used for autocompletion.
-
-* `typeahead:cursorchange` – Fired when the results container cursor moves. The 
-  event handler will be invoked with 2 arguments: the jQuery event object and 
-  the suggestion object that was moved to.
-
-* `typeahead:asyncrequest` – Fired when an async request for suggestions is 
-  sent. The event handler will be invoked with 3 arguments: the jQuery event 
-  object, the current query, and the name of the dataset the async request 
-  belongs to.
-
-* `typeahead:asynccancel` – Fired when an async request is cancelled. The event 
-  handler will be invoked with 3 arguments: the jQuery event object, the current 
-  query, and the name of the dataset the async request belonged to.
-
-* `typeahead:asyncreceive` – Fired when an async request completes. The event 
-  handler will be invoked with 3 arguments: the jQuery event object, the current 
-  query, and the name of the dataset the async request belongs to.
-
-Example usage:
-
-```
-$('.typeahead').bind('typeahead:select', function(ev, suggestion) {
-  console.log('Selection: ' + suggestion);
-});
-```
-
-**NOTE**: Every event does not supply the same arguments. See the event
-descriptions above for details on each event's argument list.
-
-<!-- section links -->
-
-[`change` event]: https://developer.mozilla.org/en-US/docs/Web/Events/change
-
-### Class Names
-
-* `input` - Added to input that's initialized into a typeahead. Defaults to 
-  `tt-input`.
-
-* `hint` - Added to hint input. Defaults to `tt-hint`.
-
-* `menu` - Added to menu element. Defaults to `tt-menu`.
-
-* `dataset` - Added to dataset elements. to Defaults to `tt-dataset`.
-
-* `suggestion` - Added to suggestion elements. Defaults to `tt-suggestion`.
-
-* `empty` - Added to menu element when it contains no content. Defaults to 
-  `tt-empty`.
-
-* `open` - Added to menu element when it is opened. Defaults to `tt-open`.
-
-* `cursor` - Added to suggestion element when menu cursor moves to said 
-  suggestion. Defaults to `tt-cursor`.
-
-* `highlight` - Added to the element that wraps highlighted text. Defaults to 
-  `tt-highlight`.
-
-To override any of these defaults, you can use the `classNames` option:
-
-```javascript
-$('.typeahead').typeahead({
-  classNames: {
-    input: 'Typeahead-input',
-    hint: 'Typeahead-hint',
-    selectable: 'Typeahead-selectable'
-  }
-});
-```

+ 0 - 234
vendor/bower-asset/typeahead.js/doc/migration/0.10.0.md

@@ -1,234 +0,0 @@
-Migrating to typeahead.js v0.10.0
-=================================
-
-Preamble
---------
-
-v0.10.0 of typeahead.js ended up being almost a complete rewrite. Many things 
-stayed the same, but there were a handful of changes you need to be aware of 
-if you plan on upgrading from an older version. This document aims to call out 
-those changes and explain what you need to do in order to have an painless 
-upgrade.
-
-Notable Changes
-----------------
-
-### First Argument to the jQuery Plugin
-
-In v0.10.0, the first argument to `jQuery#typeahead` is an options hash that
-can be used to configure the behavior of the typeahead. This is in contrast
-to previous versions where `jQuery#typeahead` expected just a series of datasets
-to be passed to it:
-
-```javascript
-// pre-v0.10.0
-$('.typeahead').typeahead(myDataset);
-
-// v0.10.0
-$('.typeahead').typeahead({
-  highlight: true,
-  hint: false
-}, myDataset);
-```
-
-If you're fine with the default configuration, you can just pass `null` as the 
-first argument:
-
-```javascript
-$('.typeahead').typeahead(null, myDataset);
-```
-
-### Bloodhound Suggestion Engine
-
-The most notable change in v0.10.0 is that typeahead.js has been decomposed into
-a suggestion engine and a UI view. As part of this change, the way you configure
-datasets has changed. Previously, a dataset config would have looked like:
-
-```javascript
-{
-  valueKey: 'num',
-  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
-  prefetch: '/prefetch',
-  remote: '/remote?q=%QUERY'
-}
-```
-
-In v0.10.0, an equivalent dataset config would look like:
-
-```javascript
-{
- displayKey: 'num',
- source: mySource
-}
-```
-
-As you can see, `local`, `prefetch`, and `remote` are no longer defined at the 
-dataset level. Instead, all you set in a dataset config is `source`. `source` is
-expected to be a function with the signature `function(query, callback)`. When a
-typeahead's query changes, suggestions will be requested from  `source`. It's
-expected `source` will compute the suggestion set and invoke `callback` with an array
-of suggestion objects. The typeahead will then go on to render those suggestions.
-
-If you're wondering if you can still configure `local`, `prefetch`, and 
-`remote`, don't worry, that's where the Bloodhound suggestion engine comes in.
-Here's how you would define `mySource` which was referenced in the previous 
-code snippet:
-
-```
-var mySource = new Bloodhound({
-  datumTokenizer: function(d) { 
-    return Bloodhound.tokenizers.whitespace(d.num); 
-  },
-  queryTokenizer: Bloodhound.tokenizers.whitespace,
-  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
-  prefetch: '/prefetch',
-  remote: '/remote?q=%QUERY'
-});
-
-// this kicks off the loading and processing of local and prefetch data
-// the suggestion engine will be useless until it is initialized
-mySource.initialize();
-```
-
-In the above snippet, a Bloodhound suggestion engine is initialized and that's 
-what will be used as the source of your dataset. There's still one last thing
-that needs to be done before you can use a Bloodhound suggestion engine as the 
-source of a dataset. Because datasets expect `source` to be function, the 
-Bloodhound instance needs to be wrapped in an adapter so it can meet that 
-expectation.
-
-```
-mySource = mySource.ttAdapter();
-```
-
-Put it all together:
-
-```javascript
-var mySource = new Bloodhound({
-  datumTokenizer: function(d) { 
-    return Bloodhound.tokenizers.whitespace(d.num); 
-  },
-  queryTokenizer: Bloodhound.tokenizers.whitespace,
-  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
-  prefetch: '/prefetch',
-  remote: '/remote?q=%QUERY'
-});
-
-mySource.initialize();
-
-$('.typeahead').typeahead(null, {
-  displayKey: 'num',
-  source: mySource.ttAdapter()
-});
-```
-
-### Tokenization Methods Must Be Provided
-
-The Bloodhound suggestion engine is token-based, so how datums and queries are
-tokenized plays a vital role in the quality of search results. Pre-v0.10.0,
-it was not possible to configure the tokenization method. Starting in v0.10.0,
-you **must** specify how you want datums and queries tokenized. 
-
-The most common tokenization methods split a given string on whitespace or 
-non-word characters. Bloodhound provides implementations for those methods
-out of the box:
-
-```javascript
-// returns ['one', 'two', 'twenty-five']
-Bloodhound.tokenizers.whitespace('  one two  twenty-five');
-
-// returns ['one', 'two', 'twenty', 'five']
-Bloodhound.tokenizers.nonword('  one two  twenty-five');
-```
-
-For query tokenization, you'll probably want to use one of the above methods.
-For datum tokenization, this is where you may want to do something a tad bit
-more advanced.
-
-For datums, sometimes you want tokens to be dervied from more than one property. 
-For example, if you were building a search engine for GitHub repositories, it'd 
-probably be wise to have tokens derived from the repo's name, owner, and 
-primary language:
-
-```javascript
-var repos = [
-  { name: 'example', owner: 'John Doe', language: 'JavaScript' },
-  { name: 'another example', owner: 'Joe Doe', language: 'Scala' }
-];
-
-function customTokenizer(datum) {
-  var nameTokens = Bloodhound.tokenizers.whitespace(datum.name);
-  var ownerTokens = Bloodhound.tokenizers.whitespace(datum.owner);
-  var languageTokens = Bloodhound.tokenizers.whitespace(datum.language);
-
-  return nameTokens.concat(ownerTokens).concat(languageTokens);
-}
-```
-
-There may also be the scenario where you want datum tokenization to be performed
-on the backend. The best way to do that is to just add a property to your datums 
-that contains those tokens. You can then provide a tokenizer that just returns 
-the already existing tokens:
-
-```javascript
-var sports = [
-  { value: 'football', tokens: ['football', 'pigskin'] },
-  { value: 'basketball', tokens: ['basketball', 'bball'] }
-];
-
-function customTokenizer(datum) { return datum.tokens; }
-```
-
-There are plenty of other ways you could go about tokenizing datums, it really
-just depends on what you are trying to accomplish.
-
-### String Datums Are No Longer Supported
-
-Dropping support for string datums was a difficult choice, but in the end it
-made sense for a number of reasons. If you still want to hydrate the suggestion 
-engine with string datums, you'll need to use the `filter` function:
-
-```javascript
-var engine = new Bloodhound({
-  prefetch: {
-    url: '/data',
-    filter: function(data) {
-      // assume data is an array of strings e.g. ['one', 'two', 'three']
-      return $.map(data, function(str) { return { value: str }; });
-    },
-    datumTokenizer: function(d) { 
-      return Bloodhound.tokenizers.whitespace(d.value); 
-    },
-    queryTokenizer: Bloodhound.tokenizers.whitespace
-  }
-});
-```
-
-### Precompiled Templates Are Now Required
-
-In previous versions of typeahead.js, you could specify a string template along
-with the templating engine that should be used to compile/render it. In 
-v0.10.0, you can no longer specify templating engines; instead you must provide
-precompiled templates. Precompiled templates are functions that take one 
-argument: the context the template should be rendered with. 
-
-Most of the popular templating engines allow for the creation of precompiled 
-templates. For example, you can generate one using Handlebars by doing the
-following:
-
-```javascript
-var precompiledTemplate = Handlebars.compile('<p>{{value}}</p>');
-```
-
-[Handlebars]: http://handlebarsjs.com/
-
-### CSS Class Changes
-
-`tt-is-under-cursor` is now `tt-cursor` - Applied to a hovered-on suggestion (either via cursor or arrow key).
-
-`tt-query` is now `tt-input` - Applied to the typeahead input field.
-
-Something Missing?
-------------------
-
-If something is missing from this migration guide, pull requests are accepted :)

+ 0 - 50
vendor/bower-asset/typeahead.js/karma.conf.js

@@ -1,50 +0,0 @@
-module.exports = function(config) {
-  config.set({
-    basePath: '',
-
-    preprocessors: {
-      'src/**/*.js': 'coverage'
-    },
-
-    reporters: ['progress', 'coverage'],
-
-    browsers: ['Chrome'],
-
-    frameworks: ['jasmine'],
-
-    coverageReporter: {
-      type: 'html',
-      dir: 'test/coverage/'
-    },
-
-    files: [
-      'bower_components/jquery/jquery.js',
-      'src/common/utils.js',
-      'src/bloodhound/version.js',
-      'src/bloodhound/tokenizers.js',
-      'src/bloodhound/lru_cache.js',
-      'src/bloodhound/persistent_storage.js',
-      'src/bloodhound/transport.js',
-      'src/bloodhound/remote.js',
-      'src/bloodhound/prefetch.js',
-      'src/bloodhound/search_index.js',
-      'src/bloodhound/options_parser.js',
-      'src/bloodhound/bloodhound.js',
-      'src/typeahead/www.js',
-      'src/typeahead/event_bus.js',
-      'src/typeahead/event_emitter.js',
-      'src/typeahead/highlight.js',
-      'src/typeahead/input.js',
-      'src/typeahead/dataset.js',
-      'src/typeahead/menu.js',
-      'src/typeahead/default_menu.js',
-      'src/typeahead/typeahead.js',
-      'src/typeahead/plugin.js',
-      'test/fixtures/**/*',
-      'bower_components/jasmine-jquery/lib/jasmine-jquery.js',
-      'bower_components/jasmine-ajax/lib/mock-ajax.js',
-      'test/helpers/**/*',
-      'test/**/*_spec.js'
-    ]
-  });
-};

+ 0 - 68
vendor/bower-asset/typeahead.js/package.json

@@ -1,68 +0,0 @@
-{
-  "name": "typeahead.js",
-  "description": "fast and fully-featured autocomplete library",
-  "keywords": [
-    "typeahead",
-    "autocomplete"
-  ],
-  "homepage": "http://twitter.github.com/typeahead.js",
-  "bugs": "https://github.com/twitter/typeahead.js/issues",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/twitter/typeahead.js.git"
-  },
-  "author": {
-    "name": "Twitter, Inc.",
-    "url": "https://twitter.com/twitteross"
-  },
-  "contributors": [
-    {
-      "name": "Jake Harding",
-      "url": "https://twitter.com/JakeHarding"
-    },
-    {
-      "name": "Tim Trueman",
-      "url": "https://twitter.com/timtrueman"
-    },
-    {
-      "name": "Veljko Skarich",
-      "url": "https://twitter.com/vskarich"
-    }
-  ],
-  "dependencies": {
-    "jquery": ">=1.7"
-  },
-  "devDependencies": {
-    "chai": "^1.9.1",
-    "colors": "^0.6.2",
-    "grunt": "~0.4",
-    "grunt-concurrent": "^0.5.0",
-    "grunt-contrib-clean": "~0.4.0",
-    "grunt-contrib-concat": "~0.1",
-    "grunt-contrib-connect": "~0.1",
-    "grunt-contrib-jshint": "~0.8",
-    "grunt-contrib-uglify": "~0.2.6",
-    "grunt-contrib-watch": "~0.2",
-    "grunt-exec": "~0.4.5",
-    "grunt-sed": "~0.1",
-    "grunt-step": "~0.2.0",
-    "grunt-umd": "^2.3.3",
-    "karma": "^0.12.22",
-    "karma-chrome-launcher": "^0.1.4",
-    "karma-coverage": "^0.2.6",
-    "karma-firefox-launcher": "^0.1.3",
-    "karma-jasmine": "^0.1.5",
-    "karma-opera-launcher": "^0.1.0",
-    "karma-phantomjs-launcher": "^0.1.4",
-    "karma-safari-launcher": "^0.1.1",
-    "mocha": "^1.20.1",
-    "semver": "~1.1.3",
-    "underscore": "^1.6.0",
-    "yiewd": "^0.5.0"
-  },
-  "scripts": {
-    "test": "./node_modules/karma/bin/karma start --single-run --browsers PhantomJS"
-  },
-  "version": "0.11.1",
-  "main": "dist/typeahead.bundle.js"
-}

+ 0 - 192
vendor/bower-asset/typeahead.js/src/bloodhound/bloodhound.js

@@ -1,192 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Bloodhound = (function() {
-  'use strict';
-
-  var old;
-
-  old = window && window.Bloodhound;
-
-  // constructor
-  // -----------
-
-  function Bloodhound(o) {
-    o = oParser(o);
-
-    this.sorter = o.sorter;
-    this.identify = o.identify;
-    this.sufficient = o.sufficient;
-
-    this.local = o.local;
-    this.remote = o.remote ? new Remote(o.remote) : null;
-    this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
-
-    // the backing data structure used for fast pattern matching
-    this.index = new SearchIndex({
-      identify: this.identify,
-      datumTokenizer: o.datumTokenizer,
-      queryTokenizer: o.queryTokenizer
-    });
-
-    // hold off on intialization if the intialize option was explicitly false
-    o.initialize !== false && this.initialize();
-  }
-
-  // static methods
-  // --------------
-
-  Bloodhound.noConflict = function noConflict() {
-    window && (window.Bloodhound = old);
-    return Bloodhound;
-  };
-
-  Bloodhound.tokenizers = tokenizers;
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Bloodhound.prototype, {
-
-    // ### super secret stuff used for integration with jquery plugin
-
-    __ttAdapter: function ttAdapter() {
-      var that = this;
-
-      return this.remote ? withAsync : withoutAsync;
-
-      function withAsync(query, sync, async) {
-        return that.search(query, sync, async);
-      }
-
-      function withoutAsync(query, sync) {
-        return that.search(query, sync);
-      }
-    },
-
-    // ### private
-
-    _loadPrefetch: function loadPrefetch() {
-      var that = this, deferred, serialized;
-
-      deferred = $.Deferred();
-
-      if (!this.prefetch) {
-        deferred.resolve();
-      }
-
-      else if (serialized = this.prefetch.fromCache()) {
-        this.index.bootstrap(serialized);
-        deferred.resolve();
-      }
-
-      else {
-        this.prefetch.fromNetwork(done);
-      }
-
-      return deferred.promise();
-
-      function done(err, data) {
-        if (err) { return deferred.reject(); }
-
-        that.add(data);
-        that.prefetch.store(that.index.serialize());
-        deferred.resolve();
-      }
-    },
-
-    _initialize: function initialize() {
-      var that = this, deferred;
-
-      // in case this is a reinitialization, clear previous data
-      this.clear();
-
-      (this.initPromise = this._loadPrefetch())
-      .done(addLocalToIndex); // local must be added to index after prefetch
-
-      return this.initPromise;
-
-      function addLocalToIndex() { that.add(that.local); }
-    },
-
-    // ### public
-
-    initialize: function initialize(force) {
-      return !this.initPromise || force ? this._initialize() : this.initPromise;
-    },
-
-    // TODO: before initialize what happens?
-    add: function add(data) {
-      this.index.add(data);
-      return this;
-    },
-
-    get: function get(ids) {
-      ids = _.isArray(ids) ? ids : [].slice.call(arguments);
-      return this.index.get(ids);
-    },
-
-    search: function search(query, sync, async) {
-      var that = this, local;
-
-      local = this.sorter(this.index.search(query));
-
-      // return a copy to guarantee no changes within this scope
-      // as this array will get used when processing the remote results
-      sync(this.remote ? local.slice() : local);
-
-      if (this.remote && local.length < this.sufficient) {
-        this.remote.get(query, processRemote);
-      }
-
-      else if (this.remote) {
-        // #149: prevents outdated rate-limited requests from being sent
-        this.remote.cancelLastRequest();
-      }
-
-      return this;
-
-      function processRemote(remote) {
-        var nonDuplicates = [];
-
-        // exclude duplicates
-        _.each(remote, function(r) {
-           !_.some(local, function(l) {
-            return that.identify(r) === that.identify(l);
-          }) && nonDuplicates.push(r);
-        });
-
-        async && async(nonDuplicates);
-      }
-    },
-
-    all: function all() {
-      return this.index.all();
-    },
-
-    clear: function clear() {
-      this.index.reset();
-      return this;
-    },
-
-    clearPrefetchCache: function clearPrefetchCache() {
-      this.prefetch && this.prefetch.clear();
-      return this;
-    },
-
-    clearRemoteCache: function clearRemoteCache() {
-      Transport.resetCache();
-      return this;
-    },
-
-    // DEPRECATED: will be removed in v1
-    ttAdapter: function ttAdapter() {
-      return this.__ttAdapter();
-    }
-  });
-
-  return Bloodhound;
-})();

+ 0 - 101
vendor/bower-asset/typeahead.js/src/bloodhound/lru_cache.js

@@ -1,101 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-// inspired by https://github.com/jharding/lru-cache
-
-var LruCache = (function() {
-  'use strict';
-
-  function LruCache(maxSize) {
-    this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
-    this.reset();
-
-    // if max size is less than 0, provide a noop cache
-    if (this.maxSize <= 0) {
-      this.set = this.get = $.noop;
-    }
-  }
-
-  _.mixin(LruCache.prototype, {
-    set: function set(key, val) {
-      var tailItem = this.list.tail, node;
-
-      // at capacity
-      if (this.size >= this.maxSize) {
-        this.list.remove(tailItem);
-        delete this.hash[tailItem.key];
-
-        this.size--;
-      }
-
-      // writing over existing key
-      if (node = this.hash[key]) {
-        node.val = val;
-        this.list.moveToFront(node);
-      }
-
-      // new key
-      else {
-        node = new Node(key, val);
-
-        this.list.add(node);
-        this.hash[key] = node;
-
-        this.size++;
-      }
-    },
-
-    get: function get(key) {
-      var node = this.hash[key];
-
-      if (node) {
-        this.list.moveToFront(node);
-        return node.val;
-      }
-    },
-
-    reset: function reset() {
-      this.size = 0;
-      this.hash = {};
-      this.list = new List();
-    }
-  });
-
-  function List() {
-    this.head = this.tail = null;
-  }
-
-  _.mixin(List.prototype, {
-    add: function add(node) {
-      if (this.head) {
-        node.next = this.head;
-        this.head.prev = node;
-      }
-
-      this.head = node;
-      this.tail = this.tail || node;
-    },
-
-    remove: function remove(node) {
-      node.prev ? node.prev.next = node.next : this.head = node.next;
-      node.next ? node.next.prev = node.prev : this.tail = node.prev;
-    },
-
-    moveToFront: function(node) {
-      this.remove(node);
-      this.add(node);
-    }
-  });
-
-  function Node(key, val) {
-    this.key = key;
-    this.val = val;
-    this.prev = this.next = null;
-  }
-
-  return LruCache;
-
-})();

+ 0 - 195
vendor/bower-asset/typeahead.js/src/bloodhound/options_parser.js

@@ -1,195 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var oParser = (function() {
-  'use strict';
-
-  return function parse(o) {
-    var defaults, sorter;
-
-    defaults = {
-      initialize: true,
-      identify: _.stringify,
-      datumTokenizer: null,
-      queryTokenizer: null,
-      sufficient: 5,
-      sorter: null,
-      local: [],
-      prefetch: null,
-      remote: null
-    };
-
-    o = _.mixin(defaults, o || {});
-
-    // throw error if required options are not set
-    !o.datumTokenizer && $.error('datumTokenizer is required');
-    !o.queryTokenizer && $.error('queryTokenizer is required');
-
-    sorter = o.sorter;
-    o.sorter = sorter ? function(x) { return x.sort(sorter); } : _.identity;
-
-    o.local = _.isFunction(o.local) ? o.local() : o.local;
-    o.prefetch = parsePrefetch(o.prefetch);
-    o.remote = parseRemote(o.remote);
-
-    return o;
-  };
-
-  function parsePrefetch(o) {
-    var defaults;
-
-    if (!o) { return null; }
-
-    defaults = {
-      url: null,
-      ttl: 24 * 60 * 60 * 1000, // 1 day
-      cache: true,
-      cacheKey: null,
-      thumbprint: '',
-      prepare: _.identity,
-      transform: _.identity,
-      transport: null
-    };
-
-    // support basic (url) and advanced configuration
-    o = _.isString(o) ? { url: o } : o;
-    o = _.mixin(defaults, o);
-
-    // throw error if required options are not set
-    !o.url && $.error('prefetch requires url to be set');
-
-    // DEPRECATED: filter will be dropped in v1
-    o.transform = o.filter || o.transform;
-
-    o.cacheKey = o.cacheKey || o.url;
-    o.thumbprint = VERSION + o.thumbprint;
-    o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-
-    return o;
-  }
-
-  function parseRemote(o) {
-    var defaults;
-
-    if (!o) { return; }
-
-    defaults = {
-      url: null,
-      cache: true, // leave undocumented
-      prepare: null,
-      replace: null,
-      wildcard: null,
-      limiter: null,
-      rateLimitBy: 'debounce',
-      rateLimitWait: 300,
-      transform: _.identity,
-      transport: null
-    };
-
-    // support basic (url) and advanced configuration
-    o = _.isString(o) ? { url: o } : o;
-    o = _.mixin(defaults, o);
-
-    // throw error if required options are not set
-    !o.url && $.error('remote requires url to be set');
-
-    // DEPRECATED: filter will be dropped in v1
-    o.transform = o.filter || o.transform;
-
-    o.prepare = toRemotePrepare(o);
-    o.limiter = toLimiter(o);
-    o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
-
-    delete o.replace;
-    delete o.wildcard;
-    delete o.rateLimitBy;
-    delete o.rateLimitWait;
-
-    return o;
-  }
-
-  function toRemotePrepare(o) {
-    var prepare, replace, wildcard;
-
-    prepare = o.prepare;
-    replace = o.replace;
-    wildcard = o.wildcard;
-
-    if (prepare) { return prepare; }
-
-    if (replace) {
-      prepare = prepareByReplace;
-    }
-
-    else if (o.wildcard) {
-      prepare = prepareByWildcard;
-    }
-
-    else {
-      prepare = idenityPrepare;
-    }
-
-    return prepare;
-
-    function prepareByReplace(query, settings) {
-      settings.url = replace(settings.url, query);
-      return settings;
-    }
-
-    function prepareByWildcard(query, settings) {
-      settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
-      return settings;
-    }
-
-    function idenityPrepare(query, settings) {
-      return settings;
-    }
-  }
-
-  function toLimiter(o) {
-    var limiter, method, wait;
-
-    limiter = o.limiter;
-    method = o.rateLimitBy;
-    wait = o.rateLimitWait;
-
-    if (!limiter) {
-      limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
-    }
-
-    return limiter;
-
-    function debounce(wait) {
-      return function debounce(fn) { return _.debounce(fn, wait); };
-    }
-
-    function throttle(wait) {
-      return function throttle(fn) { return _.throttle(fn, wait); };
-    }
-  }
-
-  function callbackToDeferred(fn) {
-    return function wrapper(o) {
-      var deferred = $.Deferred();
-
-      fn(o, onSuccess, onError);
-
-      return deferred;
-
-      function onSuccess(resp) {
-        // defer in case fn is synchronous, otherwise done
-        // and always handlers will be attached after the resolution
-        _.defer(function() { deferred.resolve(resp); });
-      }
-
-      function onError(err) {
-        // defer in case fn is synchronous, otherwise done
-        // and always handlers will be attached after the resolution
-        _.defer(function() { deferred.reject(err); });
-      }
-    };
-  }
-})();

+ 0 - 147
vendor/bower-asset/typeahead.js/src/bloodhound/persistent_storage.js

@@ -1,147 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var PersistentStorage = (function() {
-  'use strict';
-
-  var LOCAL_STORAGE;
-
-  try {
-    LOCAL_STORAGE = window.localStorage;
-
-    // while in private browsing mode, some browsers make
-    // localStorage available, but throw an error when used
-    LOCAL_STORAGE.setItem('~~~', '!');
-    LOCAL_STORAGE.removeItem('~~~');
-  } catch (err) {
-    LOCAL_STORAGE = null;
-  }
-
-  // constructor
-  // -----------
-
-  function PersistentStorage(namespace, override) {
-    this.prefix = ['__', namespace, '__'].join('');
-    this.ttlKey = '__ttl__';
-    this.keyMatcher = new RegExp('^' + _.escapeRegExChars(this.prefix));
-
-    // for testing purpose
-    this.ls = override || LOCAL_STORAGE;
-
-    // if local storage isn't available, everything becomes a noop
-    !this.ls && this._noop();
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(PersistentStorage.prototype, {
-    // ### private
-
-    _prefix: function(key) {
-      return this.prefix + key;
-    },
-
-    _ttlKey: function(key) {
-      return this._prefix(key) + this.ttlKey;
-    },
-
-    _noop: function() {
-      this.get =
-      this.set =
-      this.remove =
-      this.clear =
-      this.isExpired = _.noop;
-    },
-
-    _safeSet: function(key, val) {
-      try {
-        this.ls.setItem(key, val);
-      } catch (err) {
-        // hit the localstorage limit so clean up and better luck next time
-        if (err.name === 'QuotaExceededError') {
-          this.clear();
-          this._noop();
-        }
-      }
-    },
-
-    // ### public
-
-    get: function(key) {
-      if (this.isExpired(key)) {
-        this.remove(key);
-      }
-
-      return decode(this.ls.getItem(this._prefix(key)));
-    },
-
-    set: function(key, val, ttl) {
-      if (_.isNumber(ttl)) {
-        this._safeSet(this._ttlKey(key), encode(now() + ttl));
-      }
-
-      else {
-        this.ls.removeItem(this._ttlKey(key));
-      }
-
-      return this._safeSet(this._prefix(key), encode(val));
-    },
-
-    remove: function(key) {
-      this.ls.removeItem(this._ttlKey(key));
-      this.ls.removeItem(this._prefix(key));
-
-      return this;
-    },
-
-    clear: function() {
-      var i, keys = gatherMatchingKeys(this.keyMatcher);
-
-      for (i = keys.length; i--;) {
-        this.remove(keys[i]);
-      }
-
-      return this;
-    },
-
-    isExpired: function(key) {
-      var ttl = decode(this.ls.getItem(this._ttlKey(key)));
-
-      return _.isNumber(ttl) && now() > ttl ? true : false;
-    }
-  });
-
-  return PersistentStorage;
-
-  // helper functions
-  // ----------------
-
-  function now() {
-    return new Date().getTime();
-  }
-
-  function encode(val) {
-    // convert undefined to null to avoid issues with JSON.parse
-    return JSON.stringify(_.isUndefined(val) ? null : val);
-  }
-
-  function decode(val) {
-    return $.parseJSON(val);
-  }
-
-  function gatherMatchingKeys(keyMatcher) {
-    var i, key, keys = [], len = LOCAL_STORAGE.length;
-
-    for (i = 0; i < len; i++) {
-      if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
-        keys.push(key.replace(keyMatcher, ''));
-      }
-    }
-
-    return keys;
-  }
-})();

+ 0 - 91
vendor/bower-asset/typeahead.js/src/bloodhound/prefetch.js

@@ -1,91 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Prefetch = (function() {
-  'use strict';
-
-  var keys;
-
-  keys = { data: 'data', protocol: 'protocol', thumbprint: 'thumbprint' };
-
-  // constructor
-  // -----------
-
-  // defaults for options are handled in options_parser
-  function Prefetch(o) {
-    this.url = o.url;
-    this.ttl = o.ttl;
-    this.cache = o.cache;
-    this.prepare = o.prepare;
-    this.transform = o.transform;
-    this.transport = o.transport;
-    this.thumbprint = o.thumbprint;
-
-    this.storage = new PersistentStorage(o.cacheKey);
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Prefetch.prototype, {
-
-    // ### private
-
-    _settings: function settings() {
-      return { url: this.url, type: 'GET', dataType: 'json' };
-    },
-
-    // ### public
-
-    store: function store(data) {
-      if (!this.cache) { return; }
-
-      this.storage.set(keys.data, data, this.ttl);
-      this.storage.set(keys.protocol, location.protocol, this.ttl);
-      this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
-    },
-
-    fromCache: function fromCache() {
-      var stored = {}, isExpired;
-
-      if (!this.cache) { return null; }
-
-      stored.data = this.storage.get(keys.data);
-      stored.protocol = this.storage.get(keys.protocol);
-      stored.thumbprint = this.storage.get(keys.thumbprint);
-
-      // the stored data is considered expired if the thumbprints
-      // don't match or if the protocol it was originally stored under
-      // has changed
-      isExpired =
-        stored.thumbprint !== this.thumbprint ||
-        stored.protocol !== location.protocol;
-
-      // TODO: if expired, remove from local storage
-
-      return stored.data && !isExpired ? stored.data : null;
-    },
-
-    fromNetwork: function(cb) {
-      var that = this, settings;
-
-      if (!cb) { return; }
-
-      settings = this.prepare(this._settings());
-      this.transport(settings).fail(onError).done(onResponse);
-
-      function onError() { cb(true); }
-      function onResponse(resp) { cb(null, that.transform(resp)); }
-    },
-
-    clear: function clear() {
-      this.storage.clear();
-      return this;
-    }
-  });
-
-  return Prefetch;
-})();

+ 0 - 58
vendor/bower-asset/typeahead.js/src/bloodhound/remote.js

@@ -1,58 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Remote = (function() {
-  'use strict';
-
-  // constructor
-  // -----------
-
-  function Remote(o) {
-    this.url = o.url;
-    this.prepare = o.prepare;
-    this.transform = o.transform;
-
-    this.transport = new Transport({
-      cache: o.cache,
-      limiter: o.limiter,
-      transport: o.transport
-    });
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Remote.prototype, {
-    // ### private
-
-    _settings: function settings() {
-      return { url: this.url, type: 'GET', dataType: 'json' };
-    },
-
-    // ### public
-
-    get: function get(query, cb) {
-      var that = this, settings;
-
-      if (!cb) { return; }
-
-      query = query || '';
-      settings = this.prepare(query, this._settings());
-
-      return this.transport.get(settings, onResponse);
-
-      function onResponse(err, resp) {
-        err ? cb([]) : cb(that.transform(resp));
-      }
-    },
-
-    cancelLastRequest: function cancelLastRequest() {
-      this.transport.cancel();
-    }
-  });
-
-  return Remote;
-})();

+ 0 - 191
vendor/bower-asset/typeahead.js/src/bloodhound/search_index.js

@@ -1,191 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var SearchIndex = window.SearchIndex = (function() {
-  'use strict';
-
-  var CHILDREN = 'c', IDS = 'i';
-
-  // constructor
-  // -----------
-
-  function SearchIndex(o) {
-    o = o || {};
-
-    if (!o.datumTokenizer || !o.queryTokenizer) {
-      $.error('datumTokenizer and queryTokenizer are both required');
-    }
-
-    this.identify = o.identify || _.stringify;
-    this.datumTokenizer = o.datumTokenizer;
-    this.queryTokenizer = o.queryTokenizer;
-
-    this.reset();
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(SearchIndex.prototype, {
-
-    // ### public
-
-    bootstrap: function bootstrap(o) {
-      this.datums = o.datums;
-      this.trie = o.trie;
-    },
-
-    add: function(data) {
-      var that = this;
-
-      data = _.isArray(data) ? data : [data];
-
-      _.each(data, function(datum) {
-        var id, tokens;
-
-        that.datums[id = that.identify(datum)] = datum;
-        tokens = normalizeTokens(that.datumTokenizer(datum));
-
-        _.each(tokens, function(token) {
-          var node, chars, ch;
-
-          node = that.trie;
-          chars = token.split('');
-
-          while (ch = chars.shift()) {
-            node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
-            node[IDS].push(id);
-          }
-        });
-      });
-    },
-
-    get: function get(ids) {
-      var that = this;
-
-      return _.map(ids, function(id) { return that.datums[id]; });
-    },
-
-    search: function search(query) {
-      var that = this, tokens, matches;
-
-      tokens = normalizeTokens(this.queryTokenizer(query));
-
-      _.each(tokens, function(token) {
-        var node, chars, ch, ids;
-
-        // previous tokens didn't share any matches
-        if (matches && matches.length === 0) {
-          return false;
-        }
-
-        node = that.trie;
-        chars = token.split('');
-
-        while (node && (ch = chars.shift())) {
-          node = node[CHILDREN][ch];
-        }
-
-        if (node && chars.length === 0) {
-          ids = node[IDS].slice(0);
-          matches = matches ? getIntersection(matches, ids) : ids;
-        }
-
-        // break early if we find out there are no possible matches
-        else {
-          matches = [];
-          return false;
-        }
-      });
-
-      return matches ?
-        _.map(unique(matches), function(id) { return that.datums[id]; }) : [];
-    },
-
-    all: function all() {
-      var values = [];
-
-      for (var key in this.datums) {
-        values.push(this.datums[key]);
-      }
-
-      return values;
-    },
-
-    reset: function reset() {
-      this.datums = {};
-      this.trie = newNode();
-    },
-
-    serialize: function serialize() {
-      return { datums: this.datums, trie: this.trie };
-    }
-  });
-
-  return SearchIndex;
-
-  // helper functions
-  // ----------------
-
-  function normalizeTokens(tokens) {
-   // filter out falsy tokens
-    tokens = _.filter(tokens, function(token) { return !!token; });
-
-    // normalize tokens
-    tokens = _.map(tokens, function(token) { return token.toLowerCase(); });
-
-    return tokens;
-  }
-
-  function newNode() {
-    var node = {};
-
-    node[IDS] = [];
-    node[CHILDREN] = {};
-
-    return node;
-  }
-
-  function unique(array) {
-    var seen = {}, uniques = [];
-
-    for (var i = 0, len = array.length; i < len; i++) {
-      if (!seen[array[i]]) {
-        seen[array[i]] = true;
-        uniques.push(array[i]);
-      }
-    }
-
-    return uniques;
-  }
-
-  function getIntersection(arrayA, arrayB) {
-    var ai = 0, bi = 0, intersection = [];
-
-    arrayA = arrayA.sort();
-    arrayB = arrayB.sort();
-
-    var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
-
-    while (ai < lenArrayA && bi < lenArrayB) {
-      if (arrayA[ai] < arrayB[bi]) {
-        ai++;
-      }
-
-      else if (arrayA[ai] > arrayB[bi]) {
-        bi++;
-      }
-
-      else {
-        intersection.push(arrayA[ai]);
-        ai++;
-        bi++;
-      }
-    }
-
-    return intersection;
-  }
-})();

+ 0 - 44
vendor/bower-asset/typeahead.js/src/bloodhound/tokenizers.js

@@ -1,44 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var tokenizers = (function() {
-  'use strict';
-
-  return {
-    nonword: nonword,
-    whitespace: whitespace,
-    obj: {
-      nonword: getObjTokenizer(nonword),
-      whitespace: getObjTokenizer(whitespace)
-    }
-  };
-
-  function whitespace(str) {
-    str = _.toStr(str);
-    return str ? str.split(/\s+/) : [];
-  }
-
-  function nonword(str) {
-    str = _.toStr(str);
-    return str ? str.split(/\W+/) : [];
-  }
-
-  function getObjTokenizer(tokenizer) {
-    return function setKey(keys) {
-      keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
-
-      return function tokenize(o) {
-        var tokens = [];
-
-        _.each(keys, function(k) {
-          tokens = tokens.concat(tokenizer(_.toStr(o[k])));
-        });
-
-        return tokens;
-      };
-    };
-  }
-})();

+ 0 - 130
vendor/bower-asset/typeahead.js/src/bloodhound/transport.js

@@ -1,130 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Transport = (function() {
-  'use strict';
-
-  var pendingRequestsCount = 0,
-      pendingRequests = {},
-      maxPendingRequests = 6,
-      sharedCache = new LruCache(10);
-
-  // constructor
-  // -----------
-
-  function Transport(o) {
-    o = o || {};
-
-    this.cancelled = false;
-    this.lastReq = null;
-
-    this._send = o.transport;
-    this._get = o.limiter ? o.limiter(this._get) : this._get;
-
-    this._cache = o.cache === false ? new LruCache(0) : sharedCache;
-  }
-
-  // static methods
-  // --------------
-
-  Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
-    maxPendingRequests = num;
-  };
-
-  Transport.resetCache = function resetCache() {
-    sharedCache.reset();
-  };
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Transport.prototype, {
-
-    // ### private
-
-    _fingerprint: function fingerprint(o) {
-      o = o || {};
-      return o.url + o.type + $.param(o.data || {});
-    },
-
-    _get: function(o, cb) {
-      var that = this, fingerprint, jqXhr;
-
-      fingerprint = this._fingerprint(o);
-
-      // #149: don't make a network request if there has been a cancellation
-      // or if the url doesn't match the last url Transport#get was invoked with
-      if (this.cancelled || fingerprint !== this.lastReq) { return; }
-
-      // a request is already in progress, piggyback off of it
-      if (jqXhr = pendingRequests[fingerprint]) {
-        jqXhr.done(done).fail(fail);
-      }
-
-      // under the pending request threshold, so fire off a request
-      else if (pendingRequestsCount < maxPendingRequests) {
-        pendingRequestsCount++;
-        pendingRequests[fingerprint] =
-          this._send(o).done(done).fail(fail).always(always);
-      }
-
-      // at the pending request threshold, so hang out in the on deck circle
-      else {
-        this.onDeckRequestArgs = [].slice.call(arguments, 0);
-      }
-
-      function done(resp) {
-        cb(null, resp);
-        that._cache.set(fingerprint, resp);
-      }
-
-      function fail() {
-        cb(true);
-      }
-
-      function always() {
-        pendingRequestsCount--;
-        delete pendingRequests[fingerprint];
-
-        // ensures request is always made for the last query
-        if (that.onDeckRequestArgs) {
-          that._get.apply(that, that.onDeckRequestArgs);
-          that.onDeckRequestArgs = null;
-        }
-      }
-    },
-
-    // ### public
-
-    get: function(o, cb) {
-      var resp, fingerprint;
-
-      cb = cb || $.noop;
-      o = _.isString(o) ? { url: o } : (o || {});
-
-      fingerprint = this._fingerprint(o);
-
-      this.cancelled = false;
-      this.lastReq = fingerprint;
-
-      // in-memory cache hit
-      if (resp = this._cache.get(fingerprint)) {
-        cb(null, resp);
-      }
-
-      // go to network
-      else {
-        this._get(o, cb);
-      }
-    },
-
-    cancel: function() {
-      this.cancelled = true;
-    }
-  });
-
-  return Transport;
-})();

+ 0 - 7
vendor/bower-asset/typeahead.js/src/bloodhound/version.js

@@ -1,7 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var VERSION = '%VERSION%';

+ 0 - 164
vendor/bower-asset/typeahead.js/src/common/utils.js

@@ -1,164 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var _ = (function() {
-  'use strict';
-
-  return {
-    isMsie: function() {
-      // from https://github.com/ded/bowser/blob/master/bowser.js
-      return (/(msie|trident)/i).test(navigator.userAgent) ?
-        navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
-    },
-
-    isBlankString: function(str) { return !str || /^\s*$/.test(str); },
-
-    // http://stackoverflow.com/a/6969486
-    escapeRegExChars: function(str) {
-      return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
-    },
-
-    isString: function(obj) { return typeof obj === 'string'; },
-
-    isNumber: function(obj) { return typeof obj === 'number'; },
-
-    isArray: $.isArray,
-
-    isFunction: $.isFunction,
-
-    isObject: $.isPlainObject,
-
-    isUndefined: function(obj) { return typeof obj === 'undefined'; },
-
-    isElement: function(obj) { return !!(obj && obj.nodeType === 1); },
-
-    isJQuery: function(obj) { return obj instanceof $; },
-
-    toStr: function toStr(s) {
-      return (_.isUndefined(s) || s === null) ? '' : s + '';
-    },
-
-    bind: $.proxy,
-
-    each: function(collection, cb) {
-      // stupid argument order for jQuery.each
-      $.each(collection, reverseArgs);
-
-      function reverseArgs(index, value) { return cb(value, index); }
-    },
-
-    map: $.map,
-
-    filter: $.grep,
-
-    every: function(obj, test) {
-      var result = true;
-
-      if (!obj) { return result; }
-
-      $.each(obj, function(key, val) {
-        if (!(result = test.call(null, val, key, obj))) {
-          return false;
-        }
-      });
-
-      return !!result;
-    },
-
-    some: function(obj, test) {
-      var result = false;
-
-      if (!obj) { return result; }
-
-      $.each(obj, function(key, val) {
-        if (result = test.call(null, val, key, obj)) {
-          return false;
-        }
-      });
-
-      return !!result;
-    },
-
-    mixin: $.extend,
-
-    identity: function(x) { return x; },
-
-    clone: function(obj) { return $.extend(true, {}, obj); },
-
-    getIdGenerator: function() {
-      var counter = 0;
-      return function() { return counter++; };
-    },
-
-    templatify: function templatify(obj) {
-      return $.isFunction(obj) ? obj : template;
-
-      function template() { return String(obj); }
-    },
-
-    defer: function(fn) { setTimeout(fn, 0); },
-
-    debounce: function(func, wait, immediate) {
-      var timeout, result;
-
-      return function() {
-        var context = this, args = arguments, later, callNow;
-
-        later = function() {
-          timeout = null;
-          if (!immediate) { result = func.apply(context, args); }
-        };
-
-        callNow = immediate && !timeout;
-
-        clearTimeout(timeout);
-        timeout = setTimeout(later, wait);
-
-        if (callNow) { result = func.apply(context, args); }
-
-        return result;
-      };
-    },
-
-    throttle: function(func, wait) {
-      var context, args, timeout, result, previous, later;
-
-      previous = 0;
-      later = function() {
-        previous = new Date();
-        timeout = null;
-        result = func.apply(context, args);
-      };
-
-      return function() {
-        var now = new Date(),
-            remaining = wait - (now - previous);
-
-        context = this;
-        args = arguments;
-
-        if (remaining <= 0) {
-          clearTimeout(timeout);
-          timeout = null;
-          previous = now;
-          result = func.apply(context, args);
-        }
-
-        else if (!timeout) {
-          timeout = setTimeout(later, remaining);
-        }
-
-        return result;
-      };
-    },
-
-    stringify: function(val) {
-      return _.isString(val) ? val : JSON.stringify(val);
-    },
-
-    noop: function() {}
-  };
-})();

+ 0 - 330
vendor/bower-asset/typeahead.js/src/typeahead/dataset.js

@@ -1,330 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Dataset = (function() {
-  'use strict';
-
-  var keys, nameGenerator;
-
-  keys = {
-    val: 'tt-selectable-display',
-    obj: 'tt-selectable-object'
-  };
-
-  nameGenerator = _.getIdGenerator();
-
-  // constructor
-  // -----------
-
-  function Dataset(o, www) {
-    o = o || {};
-    o.templates = o.templates || {};
-
-    // DEPRECATED: empty will be dropped in v1
-    o.templates.notFound = o.templates.notFound || o.templates.empty;
-
-    if (!o.source) {
-      $.error('missing source');
-    }
-
-    if (!o.node) {
-      $.error('missing node');
-    }
-
-    if (o.name && !isValidName(o.name)) {
-      $.error('invalid dataset name: ' + o.name);
-    }
-
-    www.mixin(this);
-
-    this.highlight = !!o.highlight;
-    this.name = o.name || nameGenerator();
-
-    this.limit = o.limit || 5;
-    this.displayFn = getDisplayFn(o.display || o.displayKey);
-    this.templates = getTemplates(o.templates, this.displayFn);
-
-    // use duck typing to see if source is a bloodhound instance by checking
-    // for the __ttAdapter property; otherwise assume it is a function
-    this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
-
-    // if the async option is undefined, inspect the source signature as
-    // a hint to figuring out of the source will return async suggestions
-    this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
-
-    this._resetLastSuggestion();
-
-    this.$el = $(o.node)
-    .addClass(this.classes.dataset)
-    .addClass(this.classes.dataset + '-' + this.name);
-  }
-
-  // static methods
-  // --------------
-
-  Dataset.extractData = function extractData(el) {
-    var $el = $(el);
-
-    if ($el.data(keys.obj)) {
-      return {
-        val: $el.data(keys.val) || '',
-        obj: $el.data(keys.obj) || null
-      };
-    }
-
-    return null;
-  };
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Dataset.prototype, EventEmitter, {
-
-    // ### private
-
-    _overwrite: function overwrite(query, suggestions) {
-      suggestions = suggestions || [];
-
-      // got suggestions: overwrite dom with suggestions
-      if (suggestions.length) {
-        this._renderSuggestions(query, suggestions);
-      }
-
-      // no suggestions, expecting async: overwrite dom with pending
-      else if (this.async && this.templates.pending) {
-        this._renderPending(query);
-      }
-
-      // no suggestions, not expecting async: overwrite dom with not found
-      else if (!this.async && this.templates.notFound) {
-        this._renderNotFound(query);
-      }
-
-      // nothing to render: empty dom
-      else {
-        this._empty();
-      }
-
-      this.trigger('rendered', this.name, suggestions, false);
-    },
-
-    _append: function append(query, suggestions) {
-      suggestions = suggestions || [];
-
-      // got suggestions, sync suggestions exist: append suggestions to dom
-      if (suggestions.length && this.$lastSuggestion.length) {
-        this._appendSuggestions(query, suggestions);
-      }
-
-      // got suggestions, no sync suggestions: overwrite dom with suggestions
-      else if (suggestions.length) {
-        this._renderSuggestions(query, suggestions);
-      }
-
-      // no async/sync suggestions: overwrite dom with not found
-      else if (!this.$lastSuggestion.length && this.templates.notFound) {
-        this._renderNotFound(query);
-      }
-
-      this.trigger('rendered', this.name, suggestions, true);
-    },
-
-    _renderSuggestions: function renderSuggestions(query, suggestions) {
-      var $fragment;
-
-      $fragment = this._getSuggestionsFragment(query, suggestions);
-      this.$lastSuggestion = $fragment.children().last();
-
-      this.$el.html($fragment)
-      .prepend(this._getHeader(query, suggestions))
-      .append(this._getFooter(query, suggestions));
-    },
-
-    _appendSuggestions: function appendSuggestions(query, suggestions) {
-      var $fragment, $lastSuggestion;
-
-      $fragment = this._getSuggestionsFragment(query, suggestions);
-      $lastSuggestion = $fragment.children().last();
-
-      this.$lastSuggestion.after($fragment);
-
-      this.$lastSuggestion = $lastSuggestion;
-    },
-
-    _renderPending: function renderPending(query) {
-      var template = this.templates.pending;
-
-      this._resetLastSuggestion();
-      template && this.$el.html(template({
-        query: query,
-        dataset: this.name,
-      }));
-    },
-
-    _renderNotFound: function renderNotFound(query) {
-      var template = this.templates.notFound;
-
-      this._resetLastSuggestion();
-      template && this.$el.html(template({
-        query: query,
-        dataset: this.name,
-      }));
-    },
-
-    _empty: function empty() {
-      this.$el.empty();
-      this._resetLastSuggestion();
-    },
-
-    _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
-      var that = this, fragment;
-
-      fragment = document.createDocumentFragment();
-      _.each(suggestions, function getSuggestionNode(suggestion) {
-        var $el, context;
-
-        context = that._injectQuery(query, suggestion);
-
-        $el = $(that.templates.suggestion(context))
-        .data(keys.obj, suggestion)
-        .data(keys.val, that.displayFn(suggestion))
-        .addClass(that.classes.suggestion + ' ' + that.classes.selectable);
-
-        fragment.appendChild($el[0]);
-      });
-
-      this.highlight && highlight({
-        className: this.classes.highlight,
-        node: fragment,
-        pattern: query
-      });
-
-      return $(fragment);
-    },
-
-    _getFooter: function getFooter(query, suggestions) {
-      return this.templates.footer ?
-        this.templates.footer({
-          query: query,
-          suggestions: suggestions,
-          dataset: this.name
-        }) : null;
-    },
-
-    _getHeader: function getHeader(query, suggestions) {
-      return this.templates.header ?
-        this.templates.header({
-          query: query,
-          suggestions: suggestions,
-          dataset: this.name
-        }) : null;
-    },
-
-    _resetLastSuggestion: function resetLastSuggestion() {
-      this.$lastSuggestion = $();
-    },
-
-    _injectQuery: function injectQuery(query, obj) {
-      return _.isObject(obj) ? _.mixin({ _query: query }, obj) : obj;
-    },
-
-    // ### public
-
-    update: function update(query) {
-      var that = this, canceled = false, syncCalled = false, rendered = 0;
-
-      // cancel possible pending update
-      this.cancel();
-
-      this.cancel = function cancel() {
-        canceled = true;
-        that.cancel = $.noop;
-        that.async && that.trigger('asyncCanceled', query);
-      };
-
-      this.source(query, sync, async);
-      !syncCalled && sync([]);
-
-      function sync(suggestions) {
-        if (syncCalled) { return; }
-
-        syncCalled = true;
-        suggestions = (suggestions || []).slice(0, that.limit);
-        rendered = suggestions.length;
-
-        that._overwrite(query, suggestions);
-
-        if (rendered < that.limit && that.async) {
-          that.trigger('asyncRequested', query);
-        }
-      }
-
-      function async(suggestions) {
-        suggestions = suggestions || [];
-
-        // if the update has been canceled or if the query has changed
-        // do not render the suggestions as they've become outdated
-        if (!canceled && rendered < that.limit) {
-          that.cancel = $.noop;
-          rendered += suggestions.length;
-          that._append(query, suggestions.slice(0, that.limit - rendered));
-
-          that.async && that.trigger('asyncReceived', query);
-        }
-      }
-    },
-
-    // cancel function gets set in #update
-    cancel: $.noop,
-
-    clear: function clear() {
-      this._empty();
-      this.cancel();
-      this.trigger('cleared');
-    },
-
-    isEmpty: function isEmpty() {
-      return this.$el.is(':empty');
-    },
-
-    destroy: function destroy() {
-      // #970
-      this.$el = $('<div>');
-    }
-  });
-
-  return Dataset;
-
-  // helper functions
-  // ----------------
-
-  function getDisplayFn(display) {
-    display = display || _.stringify;
-
-    return _.isFunction(display) ? display : displayFn;
-
-    function displayFn(obj) { return obj[display]; }
-  }
-
-  function getTemplates(templates, displayFn) {
-    return {
-      notFound: templates.notFound && _.templatify(templates.notFound),
-      pending: templates.pending && _.templatify(templates.pending),
-      header: templates.header && _.templatify(templates.header),
-      footer: templates.footer && _.templatify(templates.footer),
-      suggestion: templates.suggestion || suggestionTemplate
-    };
-
-    function suggestionTemplate(context) {
-      return $('<div>').text(displayFn(context));
-    }
-  }
-
-  function isValidName(str) {
-    // dashes, underscores, letters, and numbers
-    return (/^[_a-zA-Z0-9-]+$/).test(str);
-  }
-})();

+ 0 - 75
vendor/bower-asset/typeahead.js/src/typeahead/default_menu.js

@@ -1,75 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var DefaultMenu = (function() {
-  'use strict';
-
-  var s = Menu.prototype;
-
-  function DefaultMenu() {
-    Menu.apply(this, [].slice.call(arguments, 0));
-  }
-
-  _.mixin(DefaultMenu.prototype, Menu.prototype, {
-    // overrides
-    // ---------
-
-    open: function open() {
-      // only display the menu when there's something to be shown
-      !this._allDatasetsEmpty() && this._show();
-      return s.open.apply(this, [].slice.call(arguments, 0));
-    },
-
-    close: function close() {
-      this._hide();
-      return s.close.apply(this, [].slice.call(arguments, 0));
-    },
-
-    _onRendered: function onRendered() {
-      if (this._allDatasetsEmpty()) {
-        this._hide();
-      }
-
-      else {
-        this.isOpen() && this._show();
-      }
-
-      return s._onRendered.apply(this, [].slice.call(arguments, 0));
-    },
-
-    _onCleared: function onCleared() {
-      if (this._allDatasetsEmpty()) {
-        this._hide();
-      }
-
-      else {
-        this.isOpen() && this._show();
-      }
-
-      return s._onCleared.apply(this, [].slice.call(arguments, 0));
-    },
-
-    setLanguageDirection: function setLanguageDirection(dir) {
-      this.$node.css(dir === 'ltr' ? this.css.ltr : this.css.rtl);
-      return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
-    },
-
-    // private
-    // ---------
-
-    _hide: function hide() {
-      this.$node.hide();
-    },
-
-    _show: function show() {
-      // can't use jQuery#show because $node is a span element we want
-      // display: block; not dislay: inline;
-      this.$node.css('display', 'block');
-    }
-  });
-
-  return DefaultMenu;
-})();

+ 0 - 78
vendor/bower-asset/typeahead.js/src/typeahead/event_bus.js

@@ -1,78 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var EventBus = (function() {
-  'use strict';
-
-  var namespace, deprecationMap;
-
-  namespace = 'typeahead:';
-
-  // DEPRECATED: will be remove in v1
-  //
-  // NOTE: there is no deprecation plan for the opened and closed event
-  // as their behavior has changed enough that it wouldn't make sense
-  deprecationMap = {
-    render: 'rendered',
-    cursorchange: 'cursorchanged',
-    select: 'selected',
-    autocomplete: 'autocompleted'
-  };
-
-  // constructor
-  // -----------
-
-  function EventBus(o) {
-    if (!o || !o.el) {
-      $.error('EventBus initialized without el');
-    }
-
-    this.$el = $(o.el);
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(EventBus.prototype, {
-
-    // ### private
-
-    _trigger: function(type, args) {
-      var $e;
-
-      $e = $.Event(namespace + type);
-      (args = args || []).unshift($e);
-
-      this.$el.trigger.apply(this.$el, args);
-
-      return $e;
-    },
-
-    // ### public
-
-    before: function(type) {
-      var args, $e;
-
-      args = [].slice.call(arguments, 1);
-      $e = this._trigger('before' + type, args);
-
-      return $e.isDefaultPrevented();
-    },
-
-    trigger: function(type) {
-      var deprecatedType;
-
-      this._trigger(type, [].slice.call(arguments, 1));
-
-      // TODO: remove in v1
-      if (deprecatedType = deprecationMap[type]) {
-        this._trigger(deprecatedType, [].slice.call(arguments, 1));
-      }
-    }
-  });
-
-  return EventBus;
-})();

+ 0 - 119
vendor/bower-asset/typeahead.js/src/typeahead/event_emitter.js

@@ -1,119 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-// inspired by https://github.com/jharding/boomerang
-
-var EventEmitter = (function() {
-  'use strict';
-
-  var splitter = /\s+/, nextTick = getNextTick();
-
-  return {
-    onSync: onSync,
-    onAsync: onAsync,
-    off: off,
-    trigger: trigger
-  };
-
-  function on(method, types, cb, context) {
-    var type;
-
-    if (!cb) { return this; }
-
-    types = types.split(splitter);
-    cb = context ? bindContext(cb, context) : cb;
-
-    this._callbacks = this._callbacks || {};
-
-    while (type = types.shift()) {
-      this._callbacks[type] = this._callbacks[type] || { sync: [], async: [] };
-      this._callbacks[type][method].push(cb);
-    }
-
-    return this;
-  }
-
-  function onAsync(types, cb, context) {
-    return on.call(this, 'async', types, cb, context);
-  }
-
-  function onSync(types, cb, context) {
-    return on.call(this, 'sync', types, cb, context);
-  }
-
-  function off(types) {
-    var type;
-
-    if (!this._callbacks) { return this; }
-
-    types = types.split(splitter);
-
-    while (type = types.shift()) {
-      delete this._callbacks[type];
-    }
-
-    return this;
-  }
-
-  function trigger(types) {
-    var type, callbacks, args, syncFlush, asyncFlush;
-
-    if (!this._callbacks) { return this; }
-
-    types = types.split(splitter);
-    args = [].slice.call(arguments, 1);
-
-    while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
-      syncFlush = getFlush(callbacks.sync, this, [type].concat(args));
-      asyncFlush = getFlush(callbacks.async, this, [type].concat(args));
-
-      syncFlush() && nextTick(asyncFlush);
-    }
-
-    return this;
-  }
-
-  function getFlush(callbacks, context, args) {
-    return flush;
-
-    function flush() {
-      var cancelled;
-
-      for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
-        // only cancel if the callback explicitly returns false
-        cancelled = callbacks[i].apply(context, args) === false;
-      }
-
-      return !cancelled;
-    }
-  }
-
-  function getNextTick() {
-    var nextTickFn;
-
-    // IE10+
-    if (window.setImmediate) {
-      nextTickFn = function nextTickSetImmediate(fn) {
-        setImmediate(function() { fn(); });
-      };
-    }
-
-    // old browsers
-    else {
-      nextTickFn = function nextTickSetTimeout(fn) {
-        setTimeout(function() { fn(); }, 0);
-      };
-    }
-
-    return nextTickFn;
-  }
-
-  function bindContext(fn, context) {
-    return fn.bind ?
-      fn.bind(context) :
-      function() { fn.apply(context, [].slice.call(arguments, 0)); };
-  }
-})();

+ 0 - 84
vendor/bower-asset/typeahead.js/src/typeahead/highlight.js

@@ -1,84 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-// inspired by https://github.com/jharding/bearhug
-
-var highlight = (function(doc) {
-  'use strict';
-
-  var defaults = {
-        node: null,
-        pattern: null,
-        tagName: 'strong',
-        className: null,
-        wordsOnly: false,
-        caseSensitive: false
-      };
-
-  return function hightlight(o) {
-    var regex;
-
-    o = _.mixin({}, defaults, o);
-
-    if (!o.node || !o.pattern) {
-      // fail silently
-      return;
-    }
-
-    // support wrapping multiple patterns
-    o.pattern = _.isArray(o.pattern) ? o.pattern : [o.pattern];
-
-    regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
-    traverse(o.node, hightlightTextNode);
-
-    function hightlightTextNode(textNode) {
-      var match, patternNode, wrapperNode;
-
-      if (match = regex.exec(textNode.data)) {
-        wrapperNode = doc.createElement(o.tagName);
-        o.className && (wrapperNode.className = o.className);
-
-        patternNode = textNode.splitText(match.index);
-        patternNode.splitText(match[0].length);
-        wrapperNode.appendChild(patternNode.cloneNode(true));
-
-        textNode.parentNode.replaceChild(wrapperNode, patternNode);
-      }
-
-      return !!match;
-    }
-
-    function traverse(el, hightlightTextNode) {
-      var childNode, TEXT_NODE_TYPE = 3;
-
-      for (var i = 0; i < el.childNodes.length; i++) {
-        childNode = el.childNodes[i];
-
-        if (childNode.nodeType === TEXT_NODE_TYPE) {
-          i += hightlightTextNode(childNode) ? 1 : 0;
-        }
-
-        else {
-          traverse(childNode, hightlightTextNode);
-        }
-      }
-    }
-  };
-
-  function getRegex(patterns, caseSensitive, wordsOnly) {
-    var escapedPatterns = [], regexStr;
-
-    for (var i = 0, len = patterns.length; i < len; i++) {
-      escapedPatterns.push(_.escapeRegExChars(patterns[i]));
-    }
-
-    regexStr = wordsOnly ?
-      '\\b(' + escapedPatterns.join('|') + ')\\b' :
-      '(' + escapedPatterns.join('|') + ')';
-
-    return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, 'i');
-  }
-})(window.document);

+ 0 - 339
vendor/bower-asset/typeahead.js/src/typeahead/input.js

@@ -1,339 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Input = (function() {
-  'use strict';
-
-  var specialKeyCodeMap;
-
-  specialKeyCodeMap = {
-    9: 'tab',
-    27: 'esc',
-    37: 'left',
-    39: 'right',
-    13: 'enter',
-    38: 'up',
-    40: 'down'
-  };
-
-  // constructor
-  // -----------
-
-  function Input(o, www) {
-    o = o || {};
-
-    if (!o.input) {
-      $.error('input is missing');
-    }
-
-    www.mixin(this);
-
-    this.$hint = $(o.hint);
-    this.$input = $(o.input);
-
-    // the query defaults to whatever the value of the input is
-    // on initialization, it'll most likely be an empty string
-    this.query = this.$input.val();
-
-    // for tracking when a change event should be triggered
-    this.queryWhenFocused = this.hasFocus() ? this.query : null;
-
-    // helps with calculating the width of the input's value
-    this.$overflowHelper = buildOverflowHelper(this.$input);
-
-    // detect the initial lang direction
-    this._checkLanguageDirection();
-
-    // if no hint, noop all the hint related functions
-    if (this.$hint.length === 0) {
-      this.setHint =
-      this.getHint =
-      this.clearHint =
-      this.clearHintIfInvalid = _.noop;
-    }
-  }
-
-  // static methods
-  // --------------
-
-  Input.normalizeQuery = function(str) {
-    // strips leading whitespace and condenses all whitespace
-    return (_.toStr(str)).replace(/^\s*/g, '').replace(/\s{2,}/g, ' ');
-  };
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Input.prototype, EventEmitter, {
-
-    // ### event handlers
-
-    _onBlur: function onBlur() {
-      this.resetInputValue();
-      this.trigger('blurred');
-    },
-
-    _onFocus: function onFocus() {
-      this.queryWhenFocused = this.query;
-      this.trigger('focused');
-    },
-
-    _onKeydown: function onKeydown($e) {
-      // which is normalized and consistent (but not for ie)
-      var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
-
-      this._managePreventDefault(keyName, $e);
-      if (keyName && this._shouldTrigger(keyName, $e)) {
-        this.trigger(keyName + 'Keyed', $e);
-      }
-    },
-
-    _onInput: function onInput() {
-      this._setQuery(this.getInputValue());
-      this.clearHintIfInvalid();
-      this._checkLanguageDirection();
-    },
-
-    // ### private
-
-    _managePreventDefault: function managePreventDefault(keyName, $e) {
-      var preventDefault;
-
-      switch (keyName) {
-        case 'up':
-        case 'down':
-          preventDefault = !withModifier($e);
-          break;
-
-        default:
-          preventDefault = false;
-      }
-
-      preventDefault && $e.preventDefault();
-    },
-
-    _shouldTrigger: function shouldTrigger(keyName, $e) {
-      var trigger;
-
-      switch (keyName) {
-        case 'tab':
-          trigger = !withModifier($e);
-          break;
-
-        default:
-          trigger = true;
-      }
-
-      return trigger;
-    },
-
-    _checkLanguageDirection: function checkLanguageDirection() {
-      var dir = (this.$input.css('direction') || 'ltr').toLowerCase();
-
-      if (this.dir !== dir) {
-        this.dir = dir;
-        this.$hint.attr('dir', dir);
-        this.trigger('langDirChanged', dir);
-      }
-    },
-
-    _setQuery: function setQuery(val, silent) {
-      var areEquivalent, hasDifferentWhitespace;
-
-      areEquivalent = areQueriesEquivalent(val, this.query);
-      hasDifferentWhitespace = areEquivalent ?
-        this.query.length !== val.length : false;
-
-      this.query = val;
-
-      if (!silent && !areEquivalent) {
-        this.trigger('queryChanged', this.query);
-      }
-
-      else if (!silent && hasDifferentWhitespace) {
-        this.trigger('whitespaceChanged', this.query);
-      }
-    },
-
-    // ### public
-
-    bind: function() {
-      var that = this, onBlur, onFocus, onKeydown, onInput;
-
-      // bound functions
-      onBlur = _.bind(this._onBlur, this);
-      onFocus = _.bind(this._onFocus, this);
-      onKeydown = _.bind(this._onKeydown, this);
-      onInput = _.bind(this._onInput, this);
-
-      this.$input
-      .on('blur.tt', onBlur)
-      .on('focus.tt', onFocus)
-      .on('keydown.tt', onKeydown);
-
-      // ie8 don't support the input event
-      // ie9 doesn't fire the input event when characters are removed
-      if (!_.isMsie() || _.isMsie() > 9) {
-        this.$input.on('input.tt', onInput);
-      }
-
-      else {
-        this.$input.on('keydown.tt keypress.tt cut.tt paste.tt', function($e) {
-          // if a special key triggered this, ignore it
-          if (specialKeyCodeMap[$e.which || $e.keyCode]) { return; }
-
-          // give the browser a chance to update the value of the input
-          // before checking to see if the query changed
-          _.defer(_.bind(that._onInput, that, $e));
-        });
-      }
-
-      return this;
-    },
-
-    focus: function focus() {
-      this.$input.focus();
-    },
-
-    blur: function blur() {
-      this.$input.blur();
-    },
-
-    getLangDir: function getLangDir() {
-      return this.dir;
-    },
-
-    getQuery: function getQuery() {
-      return this.query || '';
-    },
-
-    setQuery: function setQuery(val, silent) {
-      this.setInputValue(val);
-      this._setQuery(val, silent);
-    },
-
-    hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
-      return this.query !== this.queryWhenFocused;
-    },
-
-    getInputValue: function getInputValue() {
-      return this.$input.val();
-    },
-
-    setInputValue: function setInputValue(value) {
-      this.$input.val(value);
-      this.clearHintIfInvalid();
-      this._checkLanguageDirection();
-    },
-
-    resetInputValue: function resetInputValue() {
-      this.setInputValue(this.query);
-    },
-
-    getHint: function getHint() {
-      return this.$hint.val();
-    },
-
-    setHint: function setHint(value) {
-      this.$hint.val(value);
-    },
-
-    clearHint: function clearHint() {
-      this.setHint('');
-    },
-
-    clearHintIfInvalid: function clearHintIfInvalid() {
-      var val, hint, valIsPrefixOfHint, isValid;
-
-      val = this.getInputValue();
-      hint = this.getHint();
-      valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
-      isValid = val !== '' && valIsPrefixOfHint && !this.hasOverflow();
-
-      !isValid && this.clearHint();
-    },
-
-    hasFocus: function hasFocus() {
-      return this.$input.is(':focus');
-    },
-
-    hasOverflow: function hasOverflow() {
-      // 2 is arbitrary, just picking a small number to handle edge cases
-      var constraint = this.$input.width() - 2;
-
-      this.$overflowHelper.text(this.getInputValue());
-
-      return this.$overflowHelper.width() >= constraint;
-    },
-
-    isCursorAtEnd: function() {
-      var valueLength, selectionStart, range;
-
-      valueLength = this.$input.val().length;
-      selectionStart = this.$input[0].selectionStart;
-
-      if (_.isNumber(selectionStart)) {
-       return selectionStart === valueLength;
-      }
-
-      else if (document.selection) {
-        // NOTE: this won't work unless the input has focus, the good news
-        // is this code should only get called when the input has focus
-        range = document.selection.createRange();
-        range.moveStart('character', -valueLength);
-
-        return valueLength === range.text.length;
-      }
-
-      return true;
-    },
-
-    destroy: function destroy() {
-      this.$hint.off('.tt');
-      this.$input.off('.tt');
-      this.$overflowHelper.remove();
-
-      // #970
-      this.$hint = this.$input = this.$overflowHelper = $('<div>');
-    }
-  });
-
-  return Input;
-
-  // helper functions
-  // ----------------
-
-  function buildOverflowHelper($input) {
-    return $('<pre aria-hidden="true"></pre>')
-    .css({
-      // position helper off-screen
-      position: 'absolute',
-      visibility: 'hidden',
-      // avoid line breaks and whitespace collapsing
-      whiteSpace: 'pre',
-      // use same font css as input to calculate accurate width
-      fontFamily: $input.css('font-family'),
-      fontSize: $input.css('font-size'),
-      fontStyle: $input.css('font-style'),
-      fontVariant: $input.css('font-variant'),
-      fontWeight: $input.css('font-weight'),
-      wordSpacing: $input.css('word-spacing'),
-      letterSpacing: $input.css('letter-spacing'),
-      textIndent: $input.css('text-indent'),
-      textRendering: $input.css('text-rendering'),
-      textTransform: $input.css('text-transform')
-    })
-    .insertAfter($input);
-  }
-
-  function areQueriesEquivalent(a, b) {
-    return Input.normalizeQuery(a) === Input.normalizeQuery(b);
-  }
-
-  function withModifier($e) {
-    return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
-  }
-})();

+ 0 - 217
vendor/bower-asset/typeahead.js/src/typeahead/menu.js

@@ -1,217 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Menu = (function() {
-  'use strict';
-
-  // constructor
-  // -----------
-
-  function Menu(o, www) {
-    var that = this;
-
-    o = o || {};
-
-    if (!o.node) {
-      $.error('node is required');
-    }
-
-    www.mixin(this);
-
-    this.$node = $(o.node);
-
-    // the latest query #update was called with
-    this.query = null;
-    this.datasets = _.map(o.datasets, initializeDataset);
-
-    function initializeDataset(oDataset) {
-      var node = that.$node.find(oDataset.node).first();
-      oDataset.node = node.length ? node : $('<div>').appendTo(that.$node);
-
-      return new Dataset(oDataset, www);
-    }
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Menu.prototype, EventEmitter, {
-
-    // ### event handlers
-
-    _onSelectableClick: function onSelectableClick($e) {
-      this.trigger('selectableClicked', $($e.currentTarget));
-    },
-
-    _onRendered: function onRendered(type, dataset, suggestions, async) {
-      this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-      this.trigger('datasetRendered', dataset, suggestions, async);
-    },
-
-    _onCleared: function onCleared() {
-      this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
-      this.trigger('datasetCleared');
-    },
-
-    _propagate: function propagate() {
-      this.trigger.apply(this, arguments);
-    },
-
-    // ### private
-
-    _allDatasetsEmpty: function allDatasetsEmpty() {
-      return _.every(this.datasets, isDatasetEmpty);
-
-      function isDatasetEmpty(dataset) { return dataset.isEmpty(); }
-    },
-
-    _getSelectables: function getSelectables() {
-      return this.$node.find(this.selectors.selectable);
-    },
-
-    _removeCursor: function _removeCursor() {
-      var $selectable = this.getActiveSelectable();
-      $selectable && $selectable.removeClass(this.classes.cursor);
-    },
-
-    _ensureVisible: function ensureVisible($el) {
-      var elTop, elBottom, nodeScrollTop, nodeHeight;
-
-      elTop = $el.position().top;
-      elBottom = elTop + $el.outerHeight(true);
-      nodeScrollTop = this.$node.scrollTop();
-      nodeHeight = this.$node.height() +
-        parseInt(this.$node.css('paddingTop'), 10) +
-        parseInt(this.$node.css('paddingBottom'), 10);
-
-      if (elTop < 0) {
-        this.$node.scrollTop(nodeScrollTop + elTop);
-      }
-
-      else if (nodeHeight < elBottom) {
-        this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
-      }
-    },
-
-    // ### public
-
-    bind: function() {
-    var that = this, onSelectableClick;
-
-      onSelectableClick = _.bind(this._onSelectableClick, this);
-      this.$node.on('click.tt', this.selectors.selectable, onSelectableClick);
-
-      _.each(this.datasets, function(dataset) {
-        dataset
-        .onSync('asyncRequested', that._propagate, that)
-        .onSync('asyncCanceled', that._propagate, that)
-        .onSync('asyncReceived', that._propagate, that)
-        .onSync('rendered', that._onRendered, that)
-        .onSync('cleared', that._onCleared, that);
-      });
-
-      return this;
-    },
-
-    isOpen: function isOpen() {
-      return this.$node.hasClass(this.classes.open);
-    },
-
-    open: function open() {
-      this.$node.addClass(this.classes.open);
-    },
-
-    close: function close() {
-      this.$node.removeClass(this.classes.open);
-      this._removeCursor();
-    },
-
-    setLanguageDirection: function setLanguageDirection(dir) {
-      this.$node.attr('dir', dir);
-    },
-
-    selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
-      var $selectables, $oldCursor, oldIndex, newIndex;
-
-      $oldCursor = this.getActiveSelectable();
-      $selectables = this._getSelectables();
-
-      // shifting before and after modulo to deal with -1 index
-      oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
-      newIndex = oldIndex + delta;
-      newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
-
-      // wrap new index if less than -1
-      newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
-
-      return newIndex === -1 ? null : $selectables.eq(newIndex);
-    },
-
-    setCursor: function setCursor($selectable) {
-      this._removeCursor();
-
-      if ($selectable = $selectable && $selectable.first()) {
-        $selectable.addClass(this.classes.cursor);
-
-        // in the case of scrollable overflow
-        // make sure the cursor is visible in the node
-        this._ensureVisible($selectable);
-      }
-    },
-
-    getSelectableData: function getSelectableData($el) {
-      return ($el && $el.length) ? Dataset.extractData($el) : null;
-    },
-
-    getActiveSelectable: function getActiveSelectable() {
-      var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
-
-      return $selectable.length ? $selectable : null;
-    },
-
-    getTopSelectable: function getTopSelectable() {
-      var $selectable = this._getSelectables().first();
-
-      return $selectable.length ? $selectable : null;
-    },
-
-    update: function update(query) {
-      var isValidUpdate = query !== this.query;
-
-      // don't update if the query hasn't changed
-      if (isValidUpdate) {
-        this.query = query;
-        _.each(this.datasets, updateDataset);
-      }
-
-      return isValidUpdate;
-
-      function updateDataset(dataset) { dataset.update(query); }
-    },
-
-    empty: function empty() {
-      _.each(this.datasets, clearDataset);
-
-      this.query = null;
-      this.$node.addClass(this.classes.empty);
-
-      function clearDataset(dataset) { dataset.clear(); }
-    },
-
-    destroy: function destroy() {
-      this.$node.off('.tt');
-
-      // #970
-      this.$node = $('<div>');
-
-      _.each(this.datasets, destroyDataset);
-
-      function destroyDataset(dataset) { dataset.destroy(); }
-    }
-  });
-
-  return Menu;
-})();

+ 0 - 291
vendor/bower-asset/typeahead.js/src/typeahead/plugin.js

@@ -1,291 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-(function() {
-  'use strict';
-
-  var old, keys, methods;
-
-  old = $.fn.typeahead;
-
-  keys = {
-    www: 'tt-www',
-    attrs: 'tt-attrs',
-    typeahead: 'tt-typeahead'
-  };
-
-  methods = {
-    // supported signatures:
-    // function(o, dataset, dataset, ...)
-    // function(o, [dataset, dataset, ...])
-    initialize: function initialize(o, datasets) {
-      var www;
-
-      datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
-
-      o = o || {};
-      www = WWW(o.classNames);
-
-      return this.each(attach);
-
-      function attach() {
-        var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu,
-            eventBus, input, menu, typeahead, MenuConstructor;
-
-        // highlight is a top-level config that needs to get inherited
-        // from all of the datasets
-        _.each(datasets, function(d) { d.highlight = !!o.highlight; });
-
-        $input = $(this);
-        $wrapper = $(www.html.wrapper);
-        $hint = $elOrNull(o.hint);
-        $menu = $elOrNull(o.menu);
-
-        defaultHint = o.hint !== false && !$hint;
-        defaultMenu = o.menu !== false && !$menu;
-
-        defaultHint && ($hint = buildHintFromInput($input, www));
-        defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
-
-        // hint should be empty on init
-        $hint && $hint.val('');
-        $input = prepInput($input, www);
-
-        // only apply inline styles and make dom changes if necessary
-        if (defaultHint || defaultMenu) {
-          $wrapper.css(www.css.wrapper);
-          $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
-
-          $input
-          .wrap($wrapper)
-          .parent()
-          .prepend(defaultHint ? $hint : null)
-          .append(defaultMenu ? $menu : null);
-        }
-
-        MenuConstructor = defaultMenu ? DefaultMenu : Menu;
-
-        eventBus = new EventBus({ el: $input });
-        input = new Input({ hint: $hint, input: $input, }, www);
-        menu = new MenuConstructor({
-          node: $menu,
-          datasets: datasets
-        }, www);
-
-        typeahead = new Typeahead({
-          input: input,
-          menu: menu,
-          eventBus: eventBus,
-          minLength: o.minLength
-        }, www);
-
-        $input.data(keys.www, www);
-        $input.data(keys.typeahead, typeahead);
-      }
-    },
-
-    isEnabled: function isEnabled() {
-      var enabled;
-
-      ttEach(this.first(), function(t) { enabled = t.isEnabled(); });
-      return enabled;
-    },
-
-    enable: function enable() {
-      ttEach(this, function(t) { t.enable(); });
-      return this;
-    },
-
-    disable: function disable() {
-      ttEach(this, function(t) { t.disable(); });
-      return this;
-    },
-
-    isActive: function isActive() {
-      var active;
-
-      ttEach(this.first(), function(t) { active = t.isActive(); });
-      return active;
-    },
-
-    activate: function activate() {
-      ttEach(this, function(t) { t.activate(); });
-      return this;
-    },
-
-    deactivate: function deactivate() {
-      ttEach(this, function(t) { t.deactivate(); });
-      return this;
-    },
-
-    isOpen: function isOpen() {
-      var open;
-
-      ttEach(this.first(), function(t) { open = t.isOpen(); });
-      return open;
-    },
-
-    open: function open() {
-      ttEach(this, function(t) { t.open(); });
-      return this;
-    },
-
-    close: function close() {
-      ttEach(this, function(t) { t.close(); });
-      return this;
-    },
-
-    select: function select(el) {
-      var success = false, $el = $(el);
-
-      ttEach(this.first(), function(t) { success = t.select($el); });
-      return success;
-    },
-
-    autocomplete: function autocomplete(el) {
-      var success = false, $el = $(el);
-
-      ttEach(this.first(), function(t) { success = t.autocomplete($el); });
-      return success;
-    },
-
-    moveCursor: function moveCursoe(delta) {
-      var success = false;
-
-      ttEach(this.first(), function(t) { success = t.moveCursor(delta); });
-      return success;
-    },
-
-    // mirror jQuery#val functionality: reads opearte on first match,
-    // write operates on all matches
-    val: function val(newVal) {
-      var query;
-
-      if (!arguments.length) {
-        ttEach(this.first(), function(t) { query = t.getVal(); });
-        return query;
-      }
-
-      else {
-        ttEach(this, function(t) { t.setVal(newVal); });
-        return this;
-      }
-    },
-
-    destroy: function destroy() {
-      ttEach(this, function(typeahead, $input) {
-        revert($input);
-        typeahead.destroy();
-      });
-
-      return this;
-    }
-  };
-
-  $.fn.typeahead = function(method) {
-    // methods that should only act on intialized typeaheads
-    if (methods[method]) {
-      return methods[method].apply(this, [].slice.call(arguments, 1));
-    }
-
-    else {
-      return methods.initialize.apply(this, arguments);
-    }
-  };
-
-  $.fn.typeahead.noConflict = function noConflict() {
-    $.fn.typeahead = old;
-    return this;
-  };
-
-  // helper methods
-  // --------------
-
-  function ttEach($els, fn) {
-    $els.each(function() {
-      var $input = $(this), typeahead;
-
-      (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
-    });
-  }
-
-  function buildHintFromInput($input, www) {
-    return $input.clone()
-    .addClass(www.classes.hint)
-    .removeData()
-    .css(www.css.hint)
-    .css(getBackgroundStyles($input))
-    .prop('readonly', true)
-    .removeAttr('id name placeholder required')
-    .attr({ autocomplete: 'off', spellcheck: 'false', tabindex: -1 });
-  }
-
-  function prepInput($input, www) {
-    // store the original values of the attrs that get modified
-    // so modifications can be reverted on destroy
-    $input.data(keys.attrs, {
-      dir: $input.attr('dir'),
-      autocomplete: $input.attr('autocomplete'),
-      spellcheck: $input.attr('spellcheck'),
-      style: $input.attr('style')
-    });
-
-    $input
-    .addClass(www.classes.input)
-    .attr({ autocomplete: 'off', spellcheck: false });
-
-    // ie7 does not like it when dir is set to auto
-    try { !$input.attr('dir') && $input.attr('dir', 'auto'); } catch (e) {}
-
-    return $input;
-  }
-
-  function getBackgroundStyles($el) {
-    return {
-      backgroundAttachment: $el.css('background-attachment'),
-      backgroundClip: $el.css('background-clip'),
-      backgroundColor: $el.css('background-color'),
-      backgroundImage: $el.css('background-image'),
-      backgroundOrigin: $el.css('background-origin'),
-      backgroundPosition: $el.css('background-position'),
-      backgroundRepeat: $el.css('background-repeat'),
-      backgroundSize: $el.css('background-size')
-    };
-  }
-
-  function revert($input) {
-    var www, $wrapper;
-
-    www = $input.data(keys.www);
-    $wrapper = $input.parent().filter(www.selectors.wrapper);
-
-    // need to remove attrs that weren't previously defined and
-    // revert attrs that originally had a value
-    _.each($input.data(keys.attrs), function(val, key) {
-      _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
-    });
-
-    $input
-    .removeData(keys.typeahead)
-    .removeData(keys.www)
-    .removeData(keys.attr)
-    .removeClass(www.classes.input);
-
-    if ($wrapper.length) {
-      $input.detach().insertAfter($wrapper);
-      $wrapper.remove();
-    }
-  }
-
-  function $elOrNull(obj) {
-    var isValid, $el;
-
-    isValid = _.isJQuery(obj) || _.isElement(obj);
-    $el = isValid ? $(obj).first() : [];
-
-    return $el.length ? $el : null;
-  }
-})();

+ 0 - 438
vendor/bower-asset/typeahead.js/src/typeahead/typeahead.js

@@ -1,438 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var Typeahead = (function() {
-  'use strict';
-
-  // constructor
-  // -----------
-
-  function Typeahead(o, www) {
-    var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed,
-        onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged,
-        onWhitespaceChanged;
-
-    o = o || {};
-
-    if (!o.input) {
-      $.error('missing input');
-    }
-
-    if (!o.menu) {
-      $.error('missing menu');
-    }
-
-    if (!o.eventBus) {
-      $.error('missing event bus');
-    }
-
-    www.mixin(this);
-
-    this.eventBus = o.eventBus;
-    this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
-
-    this.input = o.input;
-    this.menu = o.menu;
-
-    this.enabled = true;
-
-    // activate the typeahead on init if the input has focus
-    this.active = false;
-    this.input.hasFocus() && this.activate();
-
-    // detect the initial lang direction
-    this.dir = this.input.getLangDir();
-
-    this._hacks();
-
-    this.menu.bind()
-    .onSync('selectableClicked', this._onSelectableClicked, this)
-    .onSync('asyncRequested', this._onAsyncRequested, this)
-    .onSync('asyncCanceled', this._onAsyncCanceled, this)
-    .onSync('asyncReceived', this._onAsyncReceived, this)
-    .onSync('datasetRendered', this._onDatasetRendered, this)
-    .onSync('datasetCleared', this._onDatasetCleared, this);
-
-    // composed event handlers for input
-    onFocused = c(this, 'activate', 'open', '_onFocused');
-    onBlurred = c(this, 'deactivate', '_onBlurred');
-    onEnterKeyed = c(this, 'isActive', 'isOpen', '_onEnterKeyed');
-    onTabKeyed = c(this, 'isActive', 'isOpen', '_onTabKeyed');
-    onEscKeyed = c(this, 'isActive', '_onEscKeyed');
-    onUpKeyed = c(this, 'isActive', 'open', '_onUpKeyed');
-    onDownKeyed = c(this, 'isActive', 'open', '_onDownKeyed');
-    onLeftKeyed = c(this, 'isActive', 'isOpen', '_onLeftKeyed');
-    onRightKeyed = c(this, 'isActive', 'isOpen', '_onRightKeyed');
-    onQueryChanged = c(this, '_openIfActive', '_onQueryChanged');
-    onWhitespaceChanged = c(this, '_openIfActive', '_onWhitespaceChanged');
-
-    this.input.bind()
-    .onSync('focused', onFocused, this)
-    .onSync('blurred', onBlurred, this)
-    .onSync('enterKeyed', onEnterKeyed, this)
-    .onSync('tabKeyed', onTabKeyed, this)
-    .onSync('escKeyed', onEscKeyed, this)
-    .onSync('upKeyed', onUpKeyed, this)
-    .onSync('downKeyed', onDownKeyed, this)
-    .onSync('leftKeyed', onLeftKeyed, this)
-    .onSync('rightKeyed', onRightKeyed, this)
-    .onSync('queryChanged', onQueryChanged, this)
-    .onSync('whitespaceChanged', onWhitespaceChanged, this)
-    .onSync('langDirChanged', this._onLangDirChanged, this);
-  }
-
-  // instance methods
-  // ----------------
-
-  _.mixin(Typeahead.prototype, {
-
-    // here's where hacks get applied and we don't feel bad about it
-    _hacks: function hacks() {
-      var $input, $menu;
-
-      // these default values are to make testing easier
-      $input = this.input.$input || $('<div>');
-      $menu = this.menu.$node || $('<div>');
-
-      // #705: if there's scrollable overflow, ie doesn't support
-      // blur cancellations when the scrollbar is clicked
-      //
-      // #351: preventDefault won't cancel blurs in ie <= 8
-      $input.on('blur.tt', function($e) {
-        var active, isActive, hasActive;
-
-        active = document.activeElement;
-        isActive = $menu.is(active);
-        hasActive = $menu.has(active).length > 0;
-
-        if (_.isMsie() && (isActive || hasActive)) {
-          $e.preventDefault();
-          // stop immediate in order to prevent Input#_onBlur from
-          // getting exectued
-          $e.stopImmediatePropagation();
-          _.defer(function() { $input.focus(); });
-        }
-      });
-
-      // #351: prevents input blur due to clicks within menu
-      $menu.on('mousedown.tt', function($e) { $e.preventDefault(); });
-    },
-
-    // ### event handlers
-
-    _onSelectableClicked: function onSelectableClicked(type, $el) {
-      this.select($el);
-    },
-
-    _onDatasetCleared: function onDatasetCleared() {
-      this._updateHint();
-    },
-
-    _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
-      this._updateHint();
-      this.eventBus.trigger('render', suggestions, async, dataset);
-    },
-
-    _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
-      this.eventBus.trigger('asyncrequest', query, dataset);
-    },
-
-    _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
-      this.eventBus.trigger('asynccancel', query, dataset);
-    },
-
-    _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
-      this.eventBus.trigger('asyncreceive', query, dataset);
-    },
-
-    _onFocused: function onFocused() {
-      this._minLengthMet() && this.menu.update(this.input.getQuery());
-    },
-
-    _onBlurred: function onBlurred() {
-      if (this.input.hasQueryChangedSinceLastFocus()) {
-        this.eventBus.trigger('change', this.input.getQuery());
-      }
-    },
-
-    _onEnterKeyed: function onEnterKeyed(type, $e) {
-      var $selectable;
-
-      if ($selectable = this.menu.getActiveSelectable()) {
-        this.select($selectable) && $e.preventDefault();
-      }
-    },
-
-    _onTabKeyed: function onTabKeyed(type, $e) {
-      var $selectable;
-
-      if ($selectable = this.menu.getActiveSelectable()) {
-        this.select($selectable) && $e.preventDefault();
-      }
-
-      else if ($selectable = this.menu.getTopSelectable()) {
-        this.autocomplete($selectable) && $e.preventDefault();
-      }
-    },
-
-    _onEscKeyed: function onEscKeyed() {
-      this.close();
-    },
-
-    _onUpKeyed: function onUpKeyed() {
-      this.moveCursor(-1);
-    },
-
-    _onDownKeyed: function onDownKeyed() {
-      this.moveCursor(+1);
-    },
-
-    _onLeftKeyed: function onLeftKeyed() {
-      if (this.dir === 'rtl' && this.input.isCursorAtEnd()) {
-        this.autocomplete(this.menu.getTopSelectable());
-      }
-    },
-
-    _onRightKeyed: function onRightKeyed() {
-      if (this.dir === 'ltr' && this.input.isCursorAtEnd()) {
-        this.autocomplete(this.menu.getTopSelectable());
-      }
-    },
-
-    _onQueryChanged: function onQueryChanged(e, query) {
-      this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
-    },
-
-    _onWhitespaceChanged: function onWhitespaceChanged() {
-      this._updateHint();
-    },
-
-    _onLangDirChanged: function onLangDirChanged(e, dir) {
-      if (this.dir !== dir) {
-        this.dir = dir;
-        this.menu.setLanguageDirection(dir);
-      }
-    },
-
-    // ### private
-
-    _openIfActive: function openIfActive() {
-      this.isActive() && this.open();
-    },
-
-    _minLengthMet: function minLengthMet(query) {
-      query = _.isString(query) ? query : (this.input.getQuery() || '');
-
-      return query.length >= this.minLength;
-    },
-
-    _updateHint: function updateHint() {
-      var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
-
-      $selectable = this.menu.getTopSelectable();
-      data = this.menu.getSelectableData($selectable);
-      val = this.input.getInputValue();
-
-      if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
-        query = Input.normalizeQuery(val);
-        escapedQuery = _.escapeRegExChars(query);
-
-        // match input value, then capture trailing text
-        frontMatchRegEx = new RegExp('^(?:' + escapedQuery + ')(.+$)', 'i');
-        match = frontMatchRegEx.exec(data.val);
-
-        // clear hint if there's no trailing text
-        match && this.input.setHint(val + match[1]);
-      }
-
-      else {
-        this.input.clearHint();
-      }
-    },
-
-    // ### public
-
-    isEnabled: function isEnabled() {
-      return this.enabled;
-    },
-
-    enable: function enable() {
-      this.enabled = true;
-    },
-
-    disable: function disable() {
-      this.enabled = false;
-    },
-
-    isActive: function isActive() {
-      return this.active;
-    },
-
-    activate: function activate() {
-      // already active
-      if (this.isActive()) {
-        return true;
-      }
-
-      // unable to activate either due to the typeahead being disabled
-      // or due to the active event being prevented
-      else if (!this.isEnabled() || this.eventBus.before('active')) {
-        return false;
-      }
-
-      // activate
-      else {
-        this.active = true;
-        this.eventBus.trigger('active');
-        return true;
-      }
-    },
-
-    deactivate: function deactivate() {
-      // already idle
-      if (!this.isActive()) {
-        return true;
-      }
-
-      // unable to deactivate due to the idle event being prevented
-      else if (this.eventBus.before('idle')) {
-        return false;
-      }
-
-      // deactivate
-      else {
-        this.active = false;
-        this.close();
-        this.eventBus.trigger('idle');
-        return true;
-      }
-    },
-
-    isOpen: function isOpen() {
-      return this.menu.isOpen();
-    },
-
-    open: function open() {
-      if (!this.isOpen() && !this.eventBus.before('open')) {
-        this.menu.open();
-        this._updateHint();
-        this.eventBus.trigger('open');
-      }
-
-      return this.isOpen();
-    },
-
-    close: function close() {
-      if (this.isOpen() && !this.eventBus.before('close')) {
-        this.menu.close();
-        this.input.clearHint();
-        this.input.resetInputValue();
-        this.eventBus.trigger('close');
-      }
-      return !this.isOpen();
-    },
-
-    setVal: function setVal(val) {
-      // expect val to be a string, so be safe, and coerce
-      this.input.setQuery(_.toStr(val));
-    },
-
-    getVal: function getVal() {
-      return this.input.getQuery();
-    },
-
-    select: function select($selectable) {
-      var data = this.menu.getSelectableData($selectable);
-
-      if (data && !this.eventBus.before('select', data.obj)) {
-        this.input.setQuery(data.val, true);
-
-        this.eventBus.trigger('select', data.obj);
-        this.close();
-
-        // return true if selection succeeded
-        return true;
-      }
-
-      return false;
-    },
-
-    autocomplete: function autocomplete($selectable) {
-      var query, data, isValid;
-
-      query = this.input.getQuery();
-      data = this.menu.getSelectableData($selectable);
-      isValid = data && query !== data.val;
-
-      if (isValid && !this.eventBus.before('autocomplete', data.obj)) {
-        this.input.setQuery(data.val);
-        this.eventBus.trigger('autocomplete', data.obj);
-
-        // return true if autocompletion succeeded
-        return true;
-      }
-
-      return false;
-    },
-
-    moveCursor: function moveCursor(delta) {
-      var query, $candidate, data, payload, cancelMove;
-
-      query = this.input.getQuery();
-      $candidate = this.menu.selectableRelativeToCursor(delta);
-      data = this.menu.getSelectableData($candidate);
-      payload = data ? data.obj : null;
-
-      // update will return true when it's a new query and new suggestions
-      // need to be fetched – in this case we don't want to move the cursor
-      cancelMove = this._minLengthMet() && this.menu.update(query);
-
-      if (!cancelMove && !this.eventBus.before('cursorchange', payload)) {
-        this.menu.setCursor($candidate);
-
-        // cursor moved to different selectable
-        if (data) {
-          this.input.setInputValue(data.val);
-        }
-
-        // cursor moved off of selectables, back to input
-        else {
-          this.input.resetInputValue();
-          this._updateHint();
-        }
-
-        this.eventBus.trigger('cursorchange', payload);
-
-        // return true if move succeeded
-        return true;
-      }
-
-      return false;
-    },
-
-    destroy: function destroy() {
-      this.input.destroy();
-      this.menu.destroy();
-    }
-  });
-
-  return Typeahead;
-
-  // helper functions
-  // ----------------
-
-  function c(ctx) {
-    var methods = [].slice.call(arguments, 1);
-
-    return function() {
-      var args = [].slice.call(arguments);
-
-      _.each(methods, function(method) {
-        return ctx[method].apply(ctx, args);
-      });
-    };
-  }
-})();

+ 0 - 113
vendor/bower-asset/typeahead.js/src/typeahead/www.js

@@ -1,113 +0,0 @@
-/*
- * typeahead.js
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-var WWW = (function() {
-  'use strict';
-
-  var defaultClassNames = {
-    wrapper: 'twitter-typeahead',
-    input: 'tt-input',
-    hint: 'tt-hint',
-    menu: 'tt-menu',
-    dataset: 'tt-dataset',
-    suggestion: 'tt-suggestion',
-    selectable: 'tt-selectable',
-    empty: 'tt-empty',
-    open: 'tt-open',
-    cursor: 'tt-cursor',
-    highlight: 'tt-highlight'
-  };
-
-  return build;
-
-  function build(o) {
-    var www, classes;
-
-    classes = _.mixin({}, defaultClassNames, o);
-
-    www = {
-      css: buildCss(),
-      classes: classes,
-      html: buildHtml(classes),
-      selectors: buildSelectors(classes)
-    };
-
-    return {
-      css: www.css,
-      html: www.html,
-      classes: www.classes,
-      selectors: www.selectors,
-      mixin: function(o) { _.mixin(o, www); }
-    };
-  }
-
-  function buildHtml(c) {
-    return {
-      wrapper: '<span class="' + c.wrapper + '"></span>',
-      menu: '<div class="' + c.menu + '"></div>'
-    };
-  }
-
-  function buildSelectors(classes) {
-    var selectors = {};
-    _.each(classes, function(v, k) { selectors[k] = '.' + v; });
-
-    return selectors;
-  }
-
-  function buildCss() {
-    var css =  {
-      wrapper: {
-        position: 'relative',
-        display: 'inline-block'
-      },
-      hint: {
-        position: 'absolute',
-        top: '0',
-        left: '0',
-        borderColor: 'transparent',
-        boxShadow: 'none',
-        // #741: fix hint opacity issue on iOS
-        opacity: '1'
-      },
-      input: {
-        position: 'relative',
-        verticalAlign: 'top',
-        backgroundColor: 'transparent'
-      },
-      inputWithNoHint: {
-        position: 'relative',
-        verticalAlign: 'top'
-      },
-      menu: {
-        position: 'absolute',
-        top: '100%',
-        left: '0',
-        zIndex: '100',
-        display: 'none'
-      },
-      ltr: {
-        left: '0',
-        right: 'auto'
-      },
-      rtl: {
-        left: 'auto',
-        right:' 0'
-      }
-    };
-
-    // ie specific styling
-    if (_.isMsie()) {
-       // ie6-8 (and 9?) doesn't fire hover and click events for elements with
-       // transparent backgrounds, for a workaround, use 1x1 transparent gif
-      _.mixin(css.input, {
-        backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)'
-      });
-    }
-
-    return css;
-  }
-})();

+ 0 - 299
vendor/bower-asset/typeahead.js/test/bloodhound/bloodhound_spec.js

@@ -1,299 +0,0 @@
-describe('Bloodhound', function() {
-
-  function build(o) {
-    return new Bloodhound(_.mixin({
-      datumTokenizer: datumTokenizer,
-      queryTokenizer: queryTokenizer
-    }, o || {}));
-  }
-
-  beforeEach(function() {
-    jasmine.Remote.useMock();
-    jasmine.Prefetch.useMock();
-    jasmine.Transport.useMock();
-    jasmine.PersistentStorage.useMock();
-  });
-
-  afterEach(function() {
-    clearAjaxRequests();
-  });
-
-  describe('#initialize', function() {
-    beforeEach(function() {
-      this.bloodhound = build({ initialize: false });
-      spyOn(this.bloodhound, '_initialize').andCallThrough();
-    });
-
-    it('should not initialize if intialize option is false', function() {
-      expect(this.bloodhound._initialize).not.toHaveBeenCalled();
-    });
-
-    it('should not support reinitialization by default', function() {
-      var p1, p2;
-
-      p1 = this.bloodhound.initialize();
-      p2 = this.bloodhound.initialize();
-
-      expect(p1).toBe(p2);
-      expect(this.bloodhound._initialize.callCount).toBe(1);
-    });
-
-    it('should reinitialize if reintialize flag is true', function() {
-      var p1, p2;
-
-      p1 = this.bloodhound.initialize();
-      p2 = this.bloodhound.initialize(true);
-
-      expect(p1).not.toBe(p2);
-      expect(this.bloodhound._initialize.callCount).toBe(2);
-    });
-
-    it('should clear the index', function() {
-      this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
-      spyOn(this.bloodhound, 'clear');
-      this.bloodhound.initialize();
-
-      expect(this.bloodhound.clear).toHaveBeenCalled();
-    });
-
-    it('should load data from prefetch cache if available', function() {
-      this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
-      this.bloodhound.prefetch.fromCache.andReturn(fixtures.serialized.simple);
-      this.bloodhound.initialize();
-
-      expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
-      expect(this.bloodhound.prefetch.fromNetwork).not.toHaveBeenCalled();
-    });
-
-    it('should load data from prefetch network as fallback', function() {
-      this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
-      this.bloodhound.prefetch.fromCache.andReturn(null);
-      this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
-      this.bloodhound.initialize();
-
-      expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
-
-      function fakeFromNetwork(cb) { cb(null, fixtures.data.simple); }
-    });
-
-    it('should store prefetch network data in the prefetch cache', function() {
-      this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
-      this.bloodhound.prefetch.fromCache.andReturn(null);
-      this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
-      this.bloodhound.initialize();
-
-      expect(this.bloodhound.prefetch.store)
-      .toHaveBeenCalledWith(fixtures.serialized.simple);
-
-      function fakeFromNetwork(cb) { cb(null, fixtures.data.simple); }
-    });
-
-    it('should add local after prefetch is loaded', function() {
-      this.bloodhound = build({
-        initialize: false,
-        local: [{ foo: 'bar' }],
-        prefetch: '/prefetch'
-      });
-      this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
-
-      expect(this.bloodhound.all()).toEqual([]);
-      this.bloodhound.initialize();
-      expect(this.bloodhound.all()).toEqual([{ foo: 'bar' }]);
-
-      function fakeFromNetwork(cb) { cb(null, []); }
-    });
-  });
-
-  describe('#add', function() {
-    it('should add datums to search index', function() {
-      var spy = jasmine.createSpy();
-
-      this.bloodhound = build().add(fixtures.data.simple);
-
-      this.bloodhound.search('big', spy);
-
-      expect(spy).toHaveBeenCalledWith([
-        { value: 'big' },
-        { value: 'bigger' },
-        { value: 'biggest' }
-      ]);
-    });
-  });
-
-  describe('#get', function() {
-    beforeEach(function() {
-      this.bloodhound = build({
-        identify: function(d) { return d.value; },
-        local: fixtures.data.simple
-      });
-    });
-
-    it('should support array signature', function() {
-      expect(this.bloodhound.get(['big', 'bigger'])).toEqual([
-        { value: 'big' },
-        { value: 'bigger' }
-      ]);
-    });
-
-    it('should support splat signature', function() {
-      expect(this.bloodhound.get('big', 'bigger')).toEqual([
-        { value: 'big' },
-        { value: 'bigger' }
-      ]);
-    });
-
-    it('should return nothing for unknown ids', function() {
-      expect(this.bloodhound.get('big', 'foo', 'bigger')).toEqual([
-        { value: 'big' },
-        { value: 'bigger' }
-      ]);
-    });
-  });
-
-  describe('#clear', function() {
-    it('should remove all datums to search index', function() {
-      var spy = jasmine.createSpy();
-
-      this.bloodhound = build({ local: fixtures.data.simple }).clear();
-
-      this.bloodhound.search('big', spy);
-
-      expect(spy).toHaveBeenCalledWith([]);
-    });
-  });
-
-  describe('#clearPrefetchCache', function() {
-    it('should clear persistent storage', function() {
-      this.bloodhound = build({ prefetch: '/prefetch' }).clearPrefetchCache();
-      expect(this.bloodhound.prefetch.clear).toHaveBeenCalled();
-    });
-  });
-
-  describe('#clearRemoteCache', function() {
-    it('should clear remote request cache', function() {
-      spyOn(Transport, 'resetCache');
-      this.bloodhound = build({ remote: '/remote' }).clearRemoteCache();
-      expect(Transport.resetCache).toHaveBeenCalled();
-    });
-  });
-
-  describe('#all', function() {
-    it('should return all local results', function() {
-      this.bloodhound = build({ local: fixtures.data.simple });
-      expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
-    });
-  });
-
-  describe('#search – local', function() {
-    it('should return sync matches', function() {
-      var spy = jasmine.createSpy();
-
-      this.bloodhound = build({ local: fixtures.data.simple });
-
-      this.bloodhound.search('big', spy);
-
-      expect(spy).toHaveBeenCalledWith([
-        { value: 'big' },
-        { value: 'bigger' },
-        { value: 'biggest' }
-      ]);
-    });
-  });
-
-  describe('#search – prefetch', function() {
-    it('should return sync matches', function() {
-      var spy = jasmine.createSpy();
-
-      this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
-      this.bloodhound.prefetch.fromCache.andReturn(fixtures.serialized.simple);
-      this.bloodhound.initialize();
-
-      this.bloodhound.search('big', spy);
-
-      expect(spy).toHaveBeenCalledWith([
-        { value: 'big' },
-        { value: 'bigger' },
-        { value: 'biggest' }
-      ]);
-    });
-  });
-
-  describe('#search – remote', function() {
-    it('should return async matches', function() {
-      var spy = jasmine.createSpy();
-
-      this.bloodhound = build({ remote: '/remote' });
-      this.bloodhound.remote.get.andCallFake(fakeGet);
-      this.bloodhound.search('dog', $.noop, spy);
-
-      expect(spy.callCount).toBe(1);
-
-      function fakeGet(o, cb) { cb(fixtures.data.animals); }
-    });
-  });
-
-  describe('#search – integration', function() {
-    it('should backfill when local/prefetch is not sufficient', function() {
-      var syncSpy, asyncSpy;
-
-      syncSpy = jasmine.createSpy();
-      asyncSpy = jasmine.createSpy();
-
-      this.bloodhound = build({
-        sufficient: 3,
-        local: fixtures.data.simple,
-        remote: '/remote'
-      });
-      this.bloodhound.remote.get.andCallFake(fakeGet);
-
-      this.bloodhound.search('big', syncSpy, asyncSpy);
-
-      expect(syncSpy).toHaveBeenCalledWith([
-        { value: 'big' },
-        { value: 'bigger' },
-        { value: 'biggest' }
-      ]);
-      expect(asyncSpy).not.toHaveBeenCalled();
-
-      this.bloodhound.search('bigg', syncSpy, asyncSpy);
-
-      expect(syncSpy).toHaveBeenCalledWith([
-        { value: 'bigger' },
-        { value: 'biggest' }
-      ]);
-      expect(asyncSpy).toHaveBeenCalledWith(fixtures.data.animals);
-
-      function fakeGet(o, cb) { cb(fixtures.data.animals); }
-    });
-
-    it('should remove duplicates from backfill', function() {
-      var syncSpy, asyncSpy;
-
-      syncSpy = jasmine.createSpy();
-      asyncSpy = jasmine.createSpy();
-
-      this.bloodhound = build({
-        identify: function(d) { return d.value; },
-        local: fixtures.data.animals,
-        remote: '/remote'
-      });
-      this.bloodhound.remote.get.andCallFake(fakeGet);
-
-      this.bloodhound.search('dog', syncSpy, asyncSpy);
-
-      expect(syncSpy).toHaveBeenCalledWith([{ value: 'dog' }]);
-      expect(asyncSpy).toHaveBeenCalledWith([
-        { value: 'cat' },
-        { value: 'moose' }
-      ]);
-
-      function fakeGet(o, cb) { cb(fixtures.data.animals); }
-    });
-  });
-
-  // helper functions
-  // ----------------
-
-  function datumTokenizer(d) { return $.trim(d.value).split(/\s+/); }
-  function queryTokenizer(s) { return $.trim(s).split(/\s+/); }
-});

+ 0 - 43
vendor/bower-asset/typeahead.js/test/bloodhound/lru_cache_spec.js

@@ -1,43 +0,0 @@
-describe('LruCache', function() {
-
-  beforeEach(function() {
-    this.cache = new LruCache(3);
-  });
-
-  it('should make entries retrievable by their keys', function() {
-    var key = 'key', val = 42;
-
-    this.cache.set(key, val);
-    expect(this.cache.get(key)).toBe(val);
-  });
-
-  it('should return undefined if key has not been set', function() {
-    expect(this.cache.get('wat?')).toBeUndefined();
-  });
-
-  it('should hold up to maxSize entries', function() {
-    this.cache.set('one', 1);
-    this.cache.set('two', 2);
-    this.cache.set('three', 3);
-    this.cache.set('four', 4);
-
-    expect(this.cache.get('one')).toBeUndefined();
-    expect(this.cache.get('two')).toBe(2);
-    expect(this.cache.get('three')).toBe(3);
-    expect(this.cache.get('four')).toBe(4);
-  });
-
-  it('should evict lru entry if cache is full', function() {
-    this.cache.set('one', 1);
-    this.cache.set('two', 2);
-    this.cache.set('three', 3);
-    this.cache.get('one');
-    this.cache.set('four', 4);
-
-    expect(this.cache.get('one')).toBe(1);
-    expect(this.cache.get('two')).toBeUndefined();
-    expect(this.cache.get('three')).toBe(3);
-    expect(this.cache.get('four')).toBe(4);
-    expect(this.cache.size).toBe(3);
-  });
-});

+ 0 - 194
vendor/bower-asset/typeahead.js/test/bloodhound/options_parser_spec.js

@@ -1,194 +0,0 @@
-describe('options parser', function() {
-
-  function build(o) {
-    return oParser(_.mixin({
-      datumTokenizer: $.noop,
-      queryTokenizer: $.noop
-    }, o || {}));
-  }
-
-  function prefetch(o) {
-    return oParser({
-      datumTokenizer: $.noop,
-      queryTokenizer: $.noop,
-      prefetch: _.mixin({
-        url: '/example'
-      }, o || {})
-    });
-  }
-
-  function remote(o) {
-    return oParser({
-      datumTokenizer: $.noop,
-      queryTokenizer: $.noop,
-      remote: _.mixin({
-        url: '/example'
-      }, o || {})
-    });
-  }
-
-  it('should throw exception if datumTokenizer is not set', function() {
-    expect(parse).toThrow();
-    function parse() { build({ datumTokenizer: null }); }
-  });
-
-  it('should throw exception if queryTokenizer is not set', function() {
-    expect(parse).toThrow();
-    function parse() { build({ queryTokenizer: null }); }
-  });
-
-  it('should wrap sorter', function() {
-    var o = build({ sorter: function(a, b) {  return a -b; } });
-    expect(o.sorter([2, 1, 3])).toEqual([1, 2, 3]);
-  });
-
-  it('should default sorter to identity function', function() {
-    var o = build();
-    expect(o.sorter([2, 1, 3])).toEqual([2, 1, 3]);
-  });
-
-  describe('local', function() {
-    it('should default to empty array', function() {
-      var o = build();
-      expect(o.local).toEqual([]);
-    });
-
-    it('should support function', function() {
-      var o = build({ local: function() { return [1]; } });
-      expect(o.local).toEqual([1]);
-    });
-
-    it('should support arrays', function() {
-      var o = build({ local: [1] });
-      expect(o.local).toEqual([1]);
-    });
-  });
-
-  describe('prefetch', function() {
-    it('should throw exception if url is not set', function() {
-      expect(parse).toThrow();
-      function parse() { prefetch({ url: null }); }
-    });
-
-    it('should support simple string format', function() {
-      expect(build({ prefetch: '/prefetch' }).prefetch).toBeDefined();
-    });
-
-    it('should default ttl to 1 day', function() {
-      var o = prefetch();
-      expect(o.prefetch.ttl).toBe(86400000);
-    });
-
-    it('should default cache to true', function() {
-      var o = prefetch();
-      expect(o.prefetch.cache).toBe(true);
-    });
-
-    it('should default transform to identiy function', function() {
-      var o = prefetch();
-      expect(o.prefetch.transform('foo')).toBe('foo');
-    });
-
-    it('should default cacheKey to url', function() {
-      var o = prefetch();
-      expect(o.prefetch.cacheKey).toBe(o.prefetch.url);
-    });
-
-    it('should default transport to jQuery.ajax', function() {
-      var o = prefetch();
-      expect(o.prefetch.transport).toBe($.ajax);
-    });
-
-    it('should prepend verison to thumbprint', function() {
-      var o = prefetch();
-      expect(o.prefetch.thumbprint).toBe('%VERSION%');
-
-      o = prefetch({ thumbprint: 'foo' });
-      expect(o.prefetch.thumbprint).toBe('%VERSION%foo');
-    });
-
-    it('should wrap custom transport to be deferred compatible', function() {
-      var o, errDeferred, successDeferred;
-
-      o = prefetch({ transport: errTransport });
-      errDeferred = o.prefetch.transport('q');
-
-      o = prefetch({ transport: successTransport });
-      successDeferred = o.prefetch.transport('q');
-
-      waits(0);
-      runs(function() {
-        expect(errDeferred.isRejected()).toBe(true);
-        expect(successDeferred.isResolved()).toBe(true);
-      });
-
-      function errTransport(q, success, error) { error(); }
-      function successTransport(q, success, error) { success(); }
-    });
-  });
-
-  describe('remote', function() {
-    it('should throw exception if url is not set', function() {
-      expect(parse).toThrow();
-      function parse() { remote({ url: null }); }
-    });
-
-    it('should support simple string format', function() {
-      expect(build({ remote: '/remote' }).remote).toBeDefined();
-    });
-
-    it('should default transform to identiy function', function() {
-      var o = remote();
-      expect(o.remote.transform('foo')).toBe('foo');
-    });
-
-    it('should default transport to jQuery.ajax', function() {
-      var o = remote();
-      expect(o.remote.transport).toBe($.ajax);
-    });
-
-    it('should default limiter to debouce', function() {
-      var o = remote();
-      expect(o.remote.limiter.name).toBe('debounce');
-    });
-
-    it('should default prepare to identity function', function() {
-      var o = remote();
-      expect(o.remote.prepare('q', { url: '/foo' })).toEqual({ url: '/foo' });
-    });
-
-    it('should support wildcard for prepare', function() {
-      var o = remote({ wildcard: '%FOO' });
-      expect(o.remote.prepare('=', { url: '/%FOO' })).toEqual({ url: '/%3D' });
-    });
-
-    it('should support replace for prepare', function() {
-      var o = remote({ replace: function() { return '/bar'; } });
-      expect(o.remote.prepare('q', { url: '/foo' })).toEqual({ url: '/bar' });
-    });
-
-    it('should should rateLimitBy for limiter', function() {
-      var o = remote({ rateLimitBy: 'throttle' });
-      expect(o.remote.limiter.name).toBe('throttle');
-    });
-
-    it('should wrap custom transport to be deferred compatible', function() {
-      var o, errDeferred, successDeferred;
-
-      o = remote({ transport: errTransport });
-      errDeferred = o.remote.transport('q');
-
-      o = remote({ transport: successTransport });
-      successDeferred = o.remote.transport('q');
-
-      waits(0);
-      runs(function() {
-        expect(errDeferred.isRejected()).toBe(true);
-        expect(successDeferred.isResolved()).toBe(true);
-      });
-
-      function errTransport(q, success, error) { error(); }
-      function successTransport(q, success, error) { success(); }
-    });
-  });
-});

+ 0 - 194
vendor/bower-asset/typeahead.js/test/bloodhound/persistent_storage_spec.js

@@ -1,194 +0,0 @@
-describe('PersistentStorage', function() {
-  var engine, ls;
-
-  // test suite is dependent on localStorage being available
-  if (!window.localStorage) {
-    console.warn('no localStorage support – skipping PersistentStorage suite');
-    return;
-  }
-
-  // for good measure!
-  localStorage.clear();
-
-  beforeEach(function() {
-    ls = {
-      get length() { return localStorage.length; },
-      key: spyThrough('key'),
-      clear: spyThrough('clear'),
-      getItem: spyThrough('getItem'),
-      setItem: spyThrough('setItem'),
-      removeItem: spyThrough('removeItem')
-    };
-
-    engine = new PersistentStorage('ns', ls);
-    spyOn(Date.prototype, 'getTime').andReturn(0);
-  });
-
-  afterEach(function() {
-    localStorage.clear();
-  });
-
-  // public methods
-  // --------------
-
-  describe('#get', function() {
-    it('should access localStorage with prefixed key', function() {
-      engine.get('key');
-      expect(ls.getItem).toHaveBeenCalledWith('__ns__key');
-    });
-
-    it('should return undefined when key does not exist', function() {
-      expect(engine.get('does not exist')).toEqual(undefined);
-    });
-
-    it('should return value as correct type', function() {
-      engine.set('string', 'i am a string');
-      engine.set('number', 42);
-      engine.set('boolean', true);
-      engine.set('null', null);
-      engine.set('object', { obj: true });
-
-      expect(engine.get('string')).toEqual('i am a string');
-      expect(engine.get('number')).toEqual(42);
-      expect(engine.get('boolean')).toEqual(true);
-      expect(engine.get('null')).toBeNull();
-      expect(engine.get('object')).toEqual({ obj: true });
-    });
-
-    it('should expire stale keys', function() {
-      engine.set('key', 'value', -1);
-
-      expect(engine.get('key')).toBeNull();
-      expect(ls.getItem('__ns__key__ttl')).toBeNull();
-    });
-  });
-
-  describe('#set', function() {
-    it('should access localStorage with prefixed key', function() {
-      engine.set('key', 'val');
-      expect(ls.setItem.mostRecentCall.args[0]).toEqual('__ns__key');
-    });
-
-    it('should JSON.stringify value before storing', function() {
-      engine.set('key', 'val');
-      expect(ls.setItem.mostRecentCall.args[1]).toEqual(JSON.stringify('val'));
-    });
-
-    it('should store ttl if provided', function() {
-      var ttl = 1;
-      engine.set('key', 'value', ttl);
-
-      expect(ls.setItem.argsForCall[0])
-      .toEqual(['__ns__key__ttl__', ttl.toString()]);
-    });
-
-    it('should call clear if the localStorage limit has been reached', function() {
-      var spy;
-
-      ls.setItem.andCallFake(function() {
-        var err = new Error();
-        err.name = 'QuotaExceededError';
-
-        throw err;
-      });
-
-      engine.clear = spy = jasmine.createSpy();
-      engine.set('key', 'value', 1);
-
-      expect(spy).toHaveBeenCalled();
-    });
-
-    it('should noop if the localStorage limit has been reached', function() {
-      var get, set, remove, clear, isExpired;
-
-      ls.setItem.andCallFake(function() {
-        var err = new Error();
-        err.name = 'QuotaExceededError';
-
-        throw err;
-      });
-
-      get = engine.get;
-      set = engine.set;
-      remove = engine.remove;
-      clear = engine.clear;
-      isExpired = engine.isExpired;
-
-      engine.set('key', 'value', 1);
-
-      expect(engine.get).not.toBe(get);
-      expect(engine.set).not.toBe(set);
-      expect(engine.remove).not.toBe(remove);
-      expect(engine.clear).not.toBe(clear);
-      expect(engine.isExpired).not.toBe(isExpired);
-    });
-  });
-
-  describe('#remove', function() {
-
-    it('should remove key from storage', function() {
-      engine.set('key', 'val');
-      engine.remove('key');
-
-      expect(engine.get('key')).toBeNull();
-    });
-  });
-
-  describe('#clear', function() {
-    it('should work with namespaces that contain regex characters', function() {
-      engine = new PersistentStorage('ns?()');
-      engine.set('key1', 'val1');
-      engine.set('key2', 'val2');
-      engine.clear();
-
-      expect(engine.get('key1')).toEqual(undefined);
-      expect(engine.get('key2')).toEqual(undefined);
-    });
-
-    it('should remove all keys that exist in namespace of engine', function() {
-      engine.set('key1', 'val1');
-      engine.set('key2', 'val2');
-      engine.set('key3', 'val3');
-      engine.set('key4', 'val4', 0);
-      engine.clear();
-
-      expect(engine.get('key1')).toEqual(undefined);
-      expect(engine.get('key2')).toEqual(undefined);
-      expect(engine.get('key3')).toEqual(undefined);
-      expect(engine.get('key4')).toEqual(undefined);
-    });
-
-    it('should not affect keys with different namespace', function() {
-      ls.setItem('diff_namespace', 'val');
-      engine.clear();
-
-      expect(ls.getItem('diff_namespace')).toEqual('val');
-    });
-  });
-
-  describe('#isExpired', function() {
-    it('should be false for keys without ttl', function() {
-      engine.set('key', 'value');
-      expect(engine.isExpired('key')).toBe(false);
-    });
-
-    it('should be false for fresh keys', function() {
-      engine.set('key', 'value', 1);
-      expect(engine.isExpired('key')).toBe(false);
-    });
-
-    it('should be true for stale keys', function() {
-      engine.set('key', 'value', -1);
-      expect(engine.isExpired('key')).toBe(true);
-    });
-  });
-
-  // compatible across browsers
-  function spyThrough(method) {
-    return jasmine.createSpy().andCallFake(fake);
-
-    function fake() {
-      return localStorage[method].apply(localStorage, arguments);
-    }
-  }
-});

+ 0 - 182
vendor/bower-asset/typeahead.js/test/bloodhound/prefetch_spec.js

@@ -1,182 +0,0 @@
-describe('Prefetch', function() {
-
-  function build(o) {
-    return new Prefetch(_.mixin({
-      url: '/prefetch',
-      ttl: 3600,
-      cache: true,
-      thumbprint: '',
-      cacheKey: 'cachekey',
-      prepare: function(x) { return x; },
-      transform: function(x) { return x; },
-      transport: $.ajax
-    }, o || {}));
-  }
-
-  beforeEach(function() {
-    jasmine.PersistentStorage.useMock();
-
-    this.prefetch = build();
-    this.storage = this.prefetch.storage;
-    this.thumbprint = this.prefetch.thumbprint;
-  });
-
-  describe('#clear', function() {
-    it('should clear cache storage', function() {
-      this.prefetch.clear();
-      expect(this.storage.clear).toHaveBeenCalled();
-    });
-  });
-
-  describe('#store', function() {
-    it('should store data in the storage cache', function() {
-      this.prefetch.store({ foo: 'bar' });
-
-      expect(this.storage.set)
-      .toHaveBeenCalledWith('data', { foo: 'bar' }, 3600);
-    });
-
-    it('should store thumbprint in the storage cache', function() {
-      this.prefetch.store({ foo: 'bar' });
-
-      expect(this.storage.set)
-      .toHaveBeenCalledWith('thumbprint', jasmine.any(String), 3600);
-    });
-
-    it('should store protocol in the storage cache', function() {
-      this.prefetch.store({ foo: 'bar' });
-
-      expect(this.storage.set)
-      .toHaveBeenCalledWith('protocol', location.protocol, 3600);
-    });
-
-    it('should be noop if cache option is false', function() {
-      this.prefetch = build({ cache: false });
-
-      this.prefetch.store({ foo: 'bar' });
-
-      expect(this.storage.set).not.toHaveBeenCalled();
-    });
-  });
-
-  describe('#fromCache', function() {
-    it('should return data if available', function() {
-      this.storage.get
-      .andCallFake(fakeStorageGet({ foo: 'bar' }, this.thumbprint));
-
-      expect(this.prefetch.fromCache()).toEqual({ foo: 'bar' });
-    });
-
-    it('should return null if data is expired', function() {
-      this.storage.get
-      .andCallFake(fakeStorageGet({ foo: 'bar' }, 'foo'));
-
-      expect(this.prefetch.fromCache()).toBeNull();
-    });
-
-    it('should return null if data does not exist', function() {
-      this.storage.get
-      .andCallFake(fakeStorageGet(null, this.thumbprint));
-
-      expect(this.prefetch.fromCache()).toBeNull();
-    });
-
-    it('should return null if cache option is false', function() {
-      this.prefetch = build({ cache: false });
-
-      this.storage.get
-      .andCallFake(fakeStorageGet({ foo: 'bar' }, this.thumbprint));
-
-      expect(this.prefetch.fromCache()).toBeNull();
-      expect(this.storage.get).not.toHaveBeenCalled();
-    });
-  });
-
-  describe('#fromNetwork', function() {
-    it('should have sensible default request settings', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.prefetch, 'transport').andReturn($.Deferred());
-
-      this.prefetch.fromNetwork(spy);
-
-      expect(this.prefetch.transport).toHaveBeenCalledWith({
-        url: '/prefetch',
-        type: 'GET',
-        dataType: 'json'
-      });
-    });
-
-    it('should transform request settings with prepare', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.prefetch, 'prepare').andReturn({ foo: 'bar' });
-      spyOn(this.prefetch, 'transport').andReturn($.Deferred());
-
-      this.prefetch.fromNetwork(spy);
-
-      expect(this.prefetch.transport).toHaveBeenCalledWith({ foo: 'bar' });
-    });
-
-    it('should transform the response using transform', function() {
-      var spy;
-
-      this.prefetch = build({
-        transform: function() { return { bar: 'foo' }; }
-      });
-
-      spy = jasmine.createSpy();
-      spyOn(this.prefetch, 'transport')
-      .andReturn($.Deferred().resolve({ foo: 'bar' }));
-
-      this.prefetch.fromNetwork(spy);
-
-      expect(spy).toHaveBeenCalledWith(null, { bar: 'foo' });
-    });
-
-    it('should invoke callback with data if success', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.prefetch, 'transport')
-      .andReturn($.Deferred().resolve({ foo: 'bar' }));
-
-      this.prefetch.fromNetwork(spy);
-
-      expect(spy).toHaveBeenCalledWith(null, { foo: 'bar' });
-    });
-
-    it('should invoke callback with err argument true if failure', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.prefetch, 'transport').andReturn($.Deferred().reject());
-
-      this.prefetch.fromNetwork(spy);
-
-      expect(spy).toHaveBeenCalledWith(true);
-    });
-  });
-
-  function fakeStorageGet(data, thumbprint, protocol) {
-    return function(key) {
-      var val;
-
-      switch (key) {
-        case 'data':
-          val = data;
-          break;
-        case 'protocol':
-          val = protocol || location.protocol;
-          break;
-        case 'thumbprint':
-          val = thumbprint;
-          break;
-      }
-
-      return val;
-    };
-  }
-});

+ 0 - 73
vendor/bower-asset/typeahead.js/test/bloodhound/remote_spec.js

@@ -1,73 +0,0 @@
-describe('Remote', function() {
-
-  beforeEach(function() {
-    jasmine.Transport.useMock();
-
-    this.remote = new Remote({
-      url: '/test?q=%QUERY',
-      prepare: function(x) { return x; },
-      transform: function(x) { return x; }
-    });
-
-    this.transport = this.remote.transport;
-  });
-
-  describe('#cancelLastRequest', function() {
-    it('should cancel last request', function() {
-      this.remote.cancelLastRequest();
-      expect(this.transport.cancel).toHaveBeenCalled();
-    });
-  });
-
-  describe('#get', function() {
-    it('should have sensible default request settings', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.remote, 'prepare');
-
-      this.remote.get('foo', spy);
-
-      expect(this.remote.prepare).toHaveBeenCalledWith('foo', {
-        url: '/test?q=%QUERY',
-        type: 'GET',
-        dataType: 'json'
-      });
-    });
-
-    it('should transform request settings with prepare', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.remote, 'prepare').andReturn([{ foo: 'bar' }]);
-
-      this.remote.get('foo', spy);
-
-      expect(this.transport.get)
-      .toHaveBeenCalledWith([{ foo: 'bar' }], jasmine.any(Function));
-    });
-
-    it('should transform response with transform', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      spyOn(this.remote, 'transform').andReturn([{ foo: 'bar' }]);
-      this.transport.get.andCallFake(function(_, cb) { cb(null, {}); });
-
-      this.remote.get('foo', spy);
-
-      expect(spy).toHaveBeenCalledWith([{ foo: 'bar' }]);
-    });
-
-    it('should return empty array on error', function() {
-      var spy;
-
-      spy = jasmine.createSpy();
-      this.transport.get.andCallFake(function(_, cb) { cb(true); });
-
-      this.remote.get('foo', spy);
-
-      expect(spy).toHaveBeenCalledWith([]);
-    });
-  });
-});

+ 0 - 72
vendor/bower-asset/typeahead.js/test/bloodhound/search_index_spec.js

@@ -1,72 +0,0 @@
-describe('SearchIndex', function() {
-
-  function build(o) {
-    return new SearchIndex(_.mixin({
-      datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
-      queryTokenizer: Bloodhound.tokenizers.whitespace
-    }, o || {}));
-  }
-
-  beforeEach(function() {
-    this.index = build();
-    this.index.add(fixtures.data.simple);
-  });
-
-  it('should support serialization/deserialization', function() {
-    var serialized = this.index.serialize();
-
-    this.index.bootstrap(serialized);
-
-    expect(this.index.search('smaller')).toEqual([{ value: 'smaller' }]);
-  });
-
-  it('should be able to add data on the fly', function() {
-    this.index.add({ value: 'new' });
-
-    expect(this.index.search('new')).toEqual([{ value: 'new' }]);
-  });
-
-  it('#get should return datums by id', function() {
-    this.index = build({ identify: function(d) { return d.value; } });
-    this.index.add(fixtures.data.simple);
-
-    expect(this.index.get(['big', 'bigger'])).toEqual([
-      { value: 'big' },
-      { value: 'bigger' }
-    ]);
-  });
-
-  it('#search should return datums that match the given query', function() {
-    expect(this.index.search('big')).toEqual([
-      { value: 'big' },
-      { value: 'bigger' },
-      { value: 'biggest' }
-    ]);
-
-    expect(this.index.search('small')).toEqual([
-      { value: 'small' },
-      { value: 'smaller' },
-      { value: 'smallest' }
-    ]);
-  });
-
-  it('#search should return an empty array of there are no matches', function() {
-    expect(this.index.search('wtf')).toEqual([]);
-  });
-
-  it('#serach should handle multi-token queries', function() {
-    this.index.add({ value: 'foo bar' });
-    expect(this.index.search('foo b')).toEqual([{ value: 'foo bar' }]);
-  });
-
-  it('#all should return all datums', function() {
-    expect(this.index.all()).toEqual(fixtures.data.simple);
-  });
-
-  it('#reset should empty the search index', function() {
-    this.index.reset();
-    expect(this.index.datums).toEqual([]);
-    expect(this.index.trie.i).toEqual([]);
-    expect(this.index.trie.c).toEqual({});
-  });
-});

+ 0 - 74
vendor/bower-asset/typeahead.js/test/bloodhound/tokenizers_spec.js

@@ -1,74 +0,0 @@
-describe('tokenizers', function() {
-
-  it('.whitespace should tokenize on whitespace', function() {
-    var tokens = tokenizers.whitespace('big-deal ok');
-    expect(tokens).toEqual(['big-deal', 'ok']);
-  });
-
-  it('.whitespace should treat null as empty string', function() {
-    var tokens = tokenizers.whitespace(null);
-    expect(tokens).toEqual([]);
-  });
-
-  it('.whitespace should treat undefined as empty string', function() {
-    var tokens = tokenizers.whitespace(undefined);
-    expect(tokens).toEqual([]);
-  });
-
-  it('.nonword should tokenize on non-word characters', function() {
-    var tokens = tokenizers.nonword('big-deal ok');
-    expect(tokens).toEqual(['big', 'deal', 'ok']);
-  });
-
-  it('.nonword should treat null as empty string', function() {
-    var tokens = tokenizers.nonword(null);
-    expect(tokens).toEqual([]);
-  });
-
-  it('.nonword should treat undefined as empty string', function() {
-    var tokens = tokenizers.nonword(undefined);
-    expect(tokens).toEqual([]);
-  });
-
-  it('.obj.whitespace should tokenize on whitespace', function() {
-    var t = tokenizers.obj.whitespace('val');
-    var tokens = t({ val: 'big-deal ok' });
-
-    expect(tokens).toEqual(['big-deal', 'ok']);
-  });
-
-  it('.obj.whitespace should accept multiple properties', function() {
-    var t = tokenizers.obj.whitespace('one', 'two');
-    var tokens = t({ one: 'big-deal ok', two: 'buzz' });
-
-    expect(tokens).toEqual(['big-deal', 'ok', 'buzz']);
-  });
-
-  it('.obj.whitespace should accept array', function() {
-    var t = tokenizers.obj.whitespace(['one', 'two']);
-    var tokens = t({ one: 'big-deal ok', two: 'buzz' });
-
-    expect(tokens).toEqual(['big-deal', 'ok', 'buzz']);
-  });
-
-  it('.obj.nonword should tokenize on non-word characters', function() {
-    var t = tokenizers.obj.nonword('val');
-    var tokens = t({ val: 'big-deal ok' });
-
-    expect(tokens).toEqual(['big', 'deal', 'ok']);
-  });
-
-  it('.obj.nonword should accept multiple properties', function() {
-    var t = tokenizers.obj.nonword('one', 'two');
-    var tokens = t({ one: 'big-deal ok', two: 'buzz' });
-
-    expect(tokens).toEqual(['big', 'deal', 'ok', 'buzz']);
-  });
-
-  it('.obj.nonword should accept array', function() {
-    var t = tokenizers.obj.nonword(['one', 'two']);
-    var tokens = t({ one: 'big-deal ok', two: 'buzz' });
-
-    expect(tokens).toEqual(['big', 'deal', 'ok', 'buzz']);
-  });
-});

+ 0 - 175
vendor/bower-asset/typeahead.js/test/bloodhound/transport_spec.js

@@ -1,175 +0,0 @@
-describe('Transport', function() {
-
-  beforeEach(function() {
-    jasmine.Ajax.useMock();
-    jasmine.Clock.useMock();
-
-    this.transport = new Transport({ transport: $.ajax });
-  });
-
-  afterEach(function() {
-    // run twice to flush out  on-deck requests
-    $.each(ajaxRequests, drop);
-    $.each(ajaxRequests, drop);
-
-    clearAjaxRequests();
-    Transport.resetCache();
-
-    function drop(i, req) {
-      req.readyState !== 4 && req.response(fixtures.ajaxResps.ok);
-    }
-  });
-
-  it('should use jQuery.ajax as the default transport mechanism', function() {
-    var req, resp = fixtures.ajaxResps.ok, spy = jasmine.createSpy();
-
-    this.transport.get('/test', spy);
-
-    req = mostRecentAjaxRequest();
-    req.response(resp);
-
-    expect(req.url).toBe('/test');
-    expect(spy).toHaveBeenCalledWith(null, resp.parsed);
-  });
-
-  it('should respect maxPendingRequests configuration', function() {
-    for (var i = 0; i < 10; i++) {
-      this.transport.get('/test' + i, $.noop);
-    }
-
-    expect(ajaxRequests.length).toBe(6);
-  });
-
-  it('should support rate limiting', function() {
-    this.transport = new Transport({ transport: $.ajax, limiter: limiter });
-
-    for (var i = 0; i < 5; i++) {
-      this.transport.get('/test' + i, $.noop);
-    }
-
-    jasmine.Clock.tick(100);
-    expect(ajaxRequests.length).toBe(1);
-
-    function limiter(fn) { return _.debounce(fn, 20); }
-  });
-
-  it('should cache most recent requests', function() {
-    var spy1 = jasmine.createSpy(), spy2 = jasmine.createSpy();
-
-    this.transport.get('/test1', $.noop);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-
-    this.transport.get('/test2', $.noop);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok1);
-
-    expect(ajaxRequests.length).toBe(2);
-
-    this.transport.get('/test1', spy1);
-    this.transport.get('/test2', spy2);
-
-    jasmine.Clock.tick(0);
-
-    // no ajax requests were made on subsequent requests
-    expect(ajaxRequests.length).toBe(2);
-
-    expect(spy1).toHaveBeenCalledWith(null, fixtures.ajaxResps.ok.parsed);
-    expect(spy2).toHaveBeenCalledWith(null, fixtures.ajaxResps.ok1.parsed);
-  });
-
-  it('should not cache requests if cache option is false', function() {
-    this.transport = new Transport({ transport: $.ajax, cache: false });
-
-    this.transport.get('/test1', $.noop);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-    this.transport.get('/test1', $.noop);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-
-    expect(ajaxRequests.length).toBe(2);
-  });
-
-  it('should prevent dog pile', function() {
-    var spy1 = jasmine.createSpy(), spy2 = jasmine.createSpy();
-
-    this.transport.get('/test1', spy1);
-    this.transport.get('/test1', spy2);
-
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-
-    expect(ajaxRequests.length).toBe(1);
-
-    waitsFor(function() { return spy1.callCount && spy2.callCount; });
-
-    runs(function() {
-      expect(spy1).toHaveBeenCalledWith(null, fixtures.ajaxResps.ok.parsed);
-      expect(spy2).toHaveBeenCalledWith(null, fixtures.ajaxResps.ok.parsed);
-    });
-  });
-
-  it('should always make a request for the last call to #get', function() {
-    var spy = jasmine.createSpy();
-
-    for (var i = 0; i < 6; i++) {
-      this.transport.get('/test' + i, $.noop);
-    }
-
-    this.transport.get('/test' + i, spy);
-    expect(ajaxRequests.length).toBe(6);
-
-    _.each(ajaxRequests, function(req) {
-      req.response(fixtures.ajaxResps.ok);
-    });
-
-    expect(ajaxRequests.length).toBe(7);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-
-    expect(spy).toHaveBeenCalled();
-  });
-
-  it('should invoke the callback with err set to true on failure', function() {
-    var req, resp = fixtures.ajaxResps.err, spy = jasmine.createSpy();
-
-    this.transport.get('/test', spy);
-
-    req = mostRecentAjaxRequest();
-    req.response(resp);
-
-    expect(req.url).toBe('/test');
-    expect(spy).toHaveBeenCalledWith(true);
-  });
-
-  it('should not send cancelled requests', function() {
-    this.transport = new Transport({ transport: $.ajax, limiter: limiter });
-
-    this.transport.get('/test', $.noop);
-    this.transport.cancel();
-
-    jasmine.Clock.tick(100);
-    expect(ajaxRequests.length).toBe(0);
-
-    function limiter(fn) { return _.debounce(fn, 20); }
-  });
-
-  it('should not send outdated requests', function() {
-    this.transport = new Transport({ transport: $.ajax, limiter: limiter });
-
-    // warm cache
-    this.transport.get('/test1', $.noop);
-    jasmine.Clock.tick(100);
-    mostRecentAjaxRequest().response(fixtures.ajaxResps.ok);
-
-    expect(mostRecentAjaxRequest().url).toBe('/test1');
-    expect(ajaxRequests.length).toBe(1);
-
-    // within the same rate-limit cycle, request test2 and test1. test2 becomes
-    // outdated after test1 is requested and no request is sent for test1
-    // because it's a cache hit
-    this.transport.get('/test2', $.noop);
-    this.transport.get('/test1', $.noop);
-
-    jasmine.Clock.tick(100);
-
-    expect(ajaxRequests.length).toBe(1);
-
-    function limiter(fn) { return _.debounce(fn, 20); }
-  });
-});

+ 0 - 12
vendor/bower-asset/typeahead.js/test/ci

@@ -1,12 +0,0 @@
-#!/bin/bash -x
-
-if [ "$TEST_SUITE" == "unit" ]; then
-  ./node_modules/karma/bin/karma start --single-run --browsers PhantomJS
-elif [ "$TRAVIS_SECURE_ENV_VARS" == "true" -a "$TEST_SUITE" == "integration" ]; then
-  static -p 8888 &
-  sleep 3
-  # integration tests are flaky, don't let them fail the build
-  ./node_modules/mocha/bin/mocha --harmony -R spec ./test/integration/test.js || true
-else
-  echo "Not running any tests"
-fi

+ 0 - 19
vendor/bower-asset/typeahead.js/test/fixtures/ajax_responses.js

@@ -1,19 +0,0 @@
-var fixtures = fixtures || {};
-
-fixtures.ajaxResps = {
-  ok: {
-    status: 200,
-    responseText: '[{ "value": "big" }, { "value": "bigger" }, { "value": "biggest" }, { "value": "small" }, { "value": "smaller" }, { "value": "smallest" }]'
-  },
-  ok1: {
-    status: 200,
-    responseText: '["dog", "cat", "moose"]'
-  },
-  err: {
-    status: 500
-  }
-};
-
-$.each(fixtures.ajaxResps, function(i, resp) {
-  resp.responseText && (resp.parsed = $.parseJSON(resp.responseText));
-});

+ 0 - 128
vendor/bower-asset/typeahead.js/test/fixtures/data.js

@@ -1,128 +0,0 @@
-var fixtures = fixtures || {};
-
-fixtures.data = {
-  simple: [
-    { value: 'big' },
-    { value: 'bigger' },
-    { value: 'biggest' },
-    { value: 'small' },
-    { value: 'smaller' },
-    { value: 'smallest' }
-  ],
-  animals: [
-    { value: 'dog' },
-    { value: 'cat' },
-    { value: 'moose' }
-  ]
-};
-
-fixtures.serialized = {
-  simple: {
-    "datums": {
-        "{\"value\":\"big\"}": {
-            "value": "big"
-        },
-        "{\"value\":\"bigger\"}": {
-            "value": "bigger"
-        },
-        "{\"value\":\"biggest\"}": {
-            "value": "biggest"
-        },
-        "{\"value\":\"small\"}": {
-            "value": "small"
-        },
-        "{\"value\":\"smaller\"}": {
-            "value": "smaller"
-        },
-        "{\"value\":\"smallest\"}": {
-            "value": "smallest"
-        }
-    },
-    "trie": {
-        "i": [],
-        "c": {
-            "b": {
-                "i": ["{\"value\":\"big\"}", "{\"value\":\"bigger\"}", "{\"value\":\"biggest\"}"],
-                "c": {
-                    "i": {
-                        "i": ["{\"value\":\"big\"}", "{\"value\":\"bigger\"}", "{\"value\":\"biggest\"}"],
-                        "c": {
-                            "g": {
-                                "i": ["{\"value\":\"big\"}", "{\"value\":\"bigger\"}", "{\"value\":\"biggest\"}"],
-                                "c": {
-                                    "g": {
-                                        "i": ["{\"value\":\"bigger\"}", "{\"value\":\"biggest\"}"],
-                                        "c": {
-                                            "e": {
-                                                "i": ["{\"value\":\"bigger\"}", "{\"value\":\"biggest\"}"],
-                                                "c": {
-                                                    "r": {
-                                                        "i": ["{\"value\":\"bigger\"}"],
-                                                        "c": {}
-                                                    },
-                                                    "s": {
-                                                        "i": ["{\"value\":\"biggest\"}"],
-                                                        "c": {
-                                                            "t": {
-                                                                "i": ["{\"value\":\"biggest\"}"],
-                                                                "c": {}
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            },
-            "s": {
-                "i": ["{\"value\":\"small\"}", "{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                "c": {
-                    "m": {
-                        "i": ["{\"value\":\"small\"}", "{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                        "c": {
-                            "a": {
-                                "i": ["{\"value\":\"small\"}", "{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                                "c": {
-                                    "l": {
-                                        "i": ["{\"value\":\"small\"}", "{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                                        "c": {
-                                            "l": {
-                                                "i": ["{\"value\":\"small\"}", "{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                                                "c": {
-                                                    "e": {
-                                                        "i": ["{\"value\":\"smaller\"}", "{\"value\":\"smallest\"}"],
-                                                        "c": {
-                                                            "r": {
-                                                                "i": ["{\"value\":\"smaller\"}"],
-                                                                "c": {}
-                                                            },
-                                                            "s": {
-                                                                "i": ["{\"value\":\"smallest\"}"],
-                                                                "c": {
-                                                                    "t": {
-                                                                        "i": ["{\"value\":\"smallest\"}"],
-                                                                        "c": {}
-                                                                    }
-                                                                }
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-}

+ 0 - 13
vendor/bower-asset/typeahead.js/test/fixtures/html.js

@@ -1,13 +0,0 @@
-var fixtures = fixtures || {};
-
-fixtures.html = {
-  input: '<input class="tt-input" type="text" autocomplete="false" spellcheck="false">',
-  hint: '<input class="tt-hint" type="text" autocomplete="false" spellcheck="false" disabled>',
-  dataset: [
-    '<div class="tt-dataset-test">',
-      '<div class="tt-selectable"><p>one</p></div>',
-      '<div class="tt-selectable"><p>two</p></div>',
-      '<div class="tt-selectable"><p>three</p></div>',
-    '</div>'
-  ].join('')
-};

Неке датотеке нису приказане због велике количине промена