cortex-reaver 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/README +1 -1
  2. data/bin/cortex_reaver +3 -4
  3. data/lib/cortex_reaver.rb +270 -110
  4. data/lib/cortex_reaver/cache.rb +23 -0
  5. data/lib/cortex_reaver/config.rb +178 -74
  6. data/lib/cortex_reaver/controller/admin.rb +64 -4
  7. data/lib/cortex_reaver/controller/comment.rb +4 -4
  8. data/lib/cortex_reaver/controller/controller.rb +3 -3
  9. data/lib/cortex_reaver/controller/journal.rb +4 -2
  10. data/lib/cortex_reaver/controller/main.rb +117 -26
  11. data/lib/cortex_reaver/controller/page.rb +7 -0
  12. data/lib/cortex_reaver/controller/photograph.rb +12 -10
  13. data/lib/cortex_reaver/controller/tag.rb +1 -1
  14. data/lib/cortex_reaver/controller/user.rb +7 -2
  15. data/lib/cortex_reaver/helper/attachments.rb +2 -2
  16. data/lib/cortex_reaver/helper/crud.rb +7 -7
  17. data/lib/cortex_reaver/helper/feeds.rb +56 -38
  18. data/lib/cortex_reaver/helper/form.rb +12 -16
  19. data/lib/cortex_reaver/helper/navigation.rb +35 -16
  20. data/lib/cortex_reaver/helper/photographs.rb +2 -2
  21. data/lib/cortex_reaver/helper/sidebar.rb +44 -0
  22. data/lib/cortex_reaver/helper/tags.rb +32 -9
  23. data/lib/cortex_reaver/helper/workflow.rb +2 -14
  24. data/lib/cortex_reaver/layout/blank.rhtml +27 -31
  25. data/lib/cortex_reaver/layout/text.rhtml +54 -67
  26. data/lib/cortex_reaver/migrations/014_convert_projects_to_pages.rb +79 -0
  27. data/lib/cortex_reaver/model/comment.rb +7 -8
  28. data/lib/cortex_reaver/model/page.rb +5 -3
  29. data/lib/cortex_reaver/model/photograph.rb +57 -13
  30. data/lib/cortex_reaver/model/tag.rb +1 -4
  31. data/lib/cortex_reaver/model/user.rb +6 -3
  32. data/lib/cortex_reaver/plugin.rb +1 -1
  33. data/lib/cortex_reaver/plugins/twitter.rb +185 -0
  34. data/lib/cortex_reaver/public/css/actions.css +31 -0
  35. data/lib/cortex_reaver/public/css/admin.css +50 -27
  36. data/lib/cortex_reaver/public/css/attachments.css +11 -0
  37. data/lib/cortex_reaver/public/css/autotags.css +38 -0
  38. data/lib/cortex_reaver/public/css/code.css +10 -2
  39. data/lib/cortex_reaver/public/css/colophon.css +10 -0
  40. data/lib/cortex_reaver/public/css/commments.css +7 -0
  41. data/lib/cortex_reaver/public/css/custom.css +1 -0
  42. data/lib/cortex_reaver/public/css/flash.css +17 -0
  43. data/lib/cortex_reaver/public/css/fonts.css +22 -0
  44. data/lib/cortex_reaver/public/css/form.css +15 -3
  45. data/lib/cortex_reaver/public/css/generics.css +39 -0
  46. data/lib/cortex_reaver/public/css/icons.css +4 -0
  47. data/lib/cortex_reaver/public/css/journals.css +3 -0
  48. data/lib/cortex_reaver/public/css/main.css +30 -312
  49. data/lib/cortex_reaver/public/css/pagination.css +50 -0
  50. data/lib/cortex_reaver/public/css/photo-show.css +87 -0
  51. data/lib/cortex_reaver/public/css/photo.css +28 -97
  52. data/lib/cortex_reaver/public/css/progress.css +35 -0
  53. data/lib/cortex_reaver/public/css/sidebar.css +83 -0
  54. data/lib/cortex_reaver/public/css/table-of-contents.css +26 -0
  55. data/lib/cortex_reaver/public/css/table.css +3 -0
  56. data/lib/cortex_reaver/public/css/tags.css +29 -0
  57. data/lib/cortex_reaver/public/css/text.css +19 -1
  58. data/lib/cortex_reaver/public/css/top_actions.css +50 -0
  59. data/lib/cortex_reaver/public/css/users.css +3 -0
  60. data/lib/cortex_reaver/public/images/admin/icons.png +0 -0
  61. data/lib/cortex_reaver/public/images/admin/icons.xcf +0 -0
  62. data/lib/cortex_reaver/public/images/background_tile.png +0 -0
  63. data/lib/cortex_reaver/public/images/edit_34.png +0 -0
  64. data/lib/cortex_reaver/public/images/edit_34_prelight.png +0 -0
  65. data/lib/cortex_reaver/public/images/elided.png +0 -0
  66. data/lib/cortex_reaver/public/images/grid_34.png +0 -0
  67. data/lib/cortex_reaver/public/images/grid_34_prelight.png +0 -0
  68. data/lib/cortex_reaver/public/images/next_11.png +0 -0
  69. data/lib/cortex_reaver/public/images/next_34.png +0 -0
  70. data/lib/cortex_reaver/public/images/next_34_prelight.png +0 -0
  71. data/lib/cortex_reaver/public/images/prev_11.png +0 -0
  72. data/lib/cortex_reaver/public/images/prev_34.png +0 -0
  73. data/lib/cortex_reaver/public/images/prev_34_prelight.png +0 -0
  74. data/lib/cortex_reaver/public/js/admin.js +15 -22
  75. data/lib/cortex_reaver/public/js/autotags.js +120 -0
  76. data/lib/cortex_reaver/public/js/jquery.autocomplete.js +135 -176
  77. data/lib/cortex_reaver/public/js/jquery.color.js +124 -0
  78. data/lib/cortex_reaver/public/js/jquery.corners.min.js +7 -0
  79. data/lib/cortex_reaver/public/js/jquery.hotkeys-0.7.9.js +244 -0
  80. data/lib/cortex_reaver/public/js/jquery.js +4361 -4
  81. data/lib/cortex_reaver/public/js/jquery.periodicalupdater.js +98 -0
  82. data/lib/cortex_reaver/public/js/photo.js +3 -32
  83. data/lib/cortex_reaver/public/robots.txt +3 -0
  84. data/lib/cortex_reaver/snippets/ramaze/cache/memcached.rb +13 -10
  85. data/lib/cortex_reaver/snippets/range.rb +9 -0
  86. data/lib/cortex_reaver/support/attachments.rb +12 -0
  87. data/lib/cortex_reaver/support/comments.rb +1 -3
  88. data/lib/cortex_reaver/support/renderer.rb +20 -17
  89. data/lib/cortex_reaver/support/sequenceable.rb +6 -6
  90. data/lib/cortex_reaver/support/tags.rb +15 -7
  91. data/lib/cortex_reaver/version.rb +1 -1
  92. data/lib/cortex_reaver/view/admin/configuration.rhtml +7 -0
  93. data/lib/cortex_reaver/view/admin/index.rhtml +3 -0
  94. data/lib/cortex_reaver/view/admin/regenerate_photo_sizes.rhtml +16 -0
  95. data/lib/cortex_reaver/view/adminbox.rhtml +34 -44
  96. data/lib/cortex_reaver/view/comments/comment.rhtml +1 -1
  97. data/lib/cortex_reaver/view/comments/form.rhtml +1 -2
  98. data/lib/cortex_reaver/view/comments/post_form.rhtml +2 -10
  99. data/lib/cortex_reaver/view/head.rhtml +11 -0
  100. data/lib/cortex_reaver/view/journals/journal.rhtml +3 -3
  101. data/lib/cortex_reaver/view/journals/show.rhtml +0 -4
  102. data/lib/cortex_reaver/view/js.rhtml +1 -0
  103. data/lib/cortex_reaver/view/pages/list.rhtml +3 -23
  104. data/lib/cortex_reaver/view/pages/row.rhtml +13 -0
  105. data/lib/cortex_reaver/view/photographs/grid.rhtml +30 -36
  106. data/lib/cortex_reaver/view/photographs/show.rhtml +42 -108
  107. data/lib/cortex_reaver/view/sidebar/explore_photos.rhtml +7 -0
  108. data/lib/cortex_reaver/view/sidebar/photographs.rhtml +15 -0
  109. data/lib/cortex_reaver/view/sidebar/sections.rhtml +4 -0
  110. data/lib/cortex_reaver/view/sidebar/twitter.rhtml +12 -0
  111. data/lib/cortex_reaver/view/tags/show.rhtml +0 -10
  112. data/lib/cortex_reaver/view/tracker.rhtml +0 -0
  113. data/lib/cortex_reaver/view/users/list.rhtml +1 -7
  114. data/lib/cortex_reaver/view/users/login.rhtml +1 -1
  115. metadata +103 -43
  116. data/lib/cortex_reaver/controller/project.rb +0 -53
  117. data/lib/cortex_reaver/helper/template.rb +0 -37
  118. data/lib/cortex_reaver/model/project.rb +0 -57
  119. data/lib/cortex_reaver/public/css/ramaze_error.css +0 -90
  120. data/lib/cortex_reaver/public/images/atom-xml-icon.png +0 -0
  121. data/lib/cortex_reaver/public/images/body.png +0 -0
  122. data/lib/cortex_reaver/public/images/border_bottom.png +0 -0
  123. data/lib/cortex_reaver/public/images/border_bottom_left.png +0 -0
  124. data/lib/cortex_reaver/public/images/border_bottom_right.png +0 -0
  125. data/lib/cortex_reaver/public/images/border_left.png +0 -0
  126. data/lib/cortex_reaver/public/images/border_right.png +0 -0
  127. data/lib/cortex_reaver/public/images/border_top.png +0 -0
  128. data/lib/cortex_reaver/public/images/border_top_left.png +0 -0
  129. data/lib/cortex_reaver/public/images/border_top_right.png +0 -0
  130. data/lib/cortex_reaver/public/images/header.png +0 -0
  131. data/lib/cortex_reaver/public/images/header.xcf +0 -0
  132. data/lib/cortex_reaver/public/images/indicator.gif +0 -0
  133. data/lib/cortex_reaver/public/images/rss-xml-icon.png +0 -0
  134. data/lib/cortex_reaver/public/images/sections.png +0 -0
  135. data/lib/cortex_reaver/public/images/sections_highlight.png +0 -0
  136. data/lib/cortex_reaver/public/js/jquery.autocompletefb.js +0 -125
  137. data/lib/cortex_reaver/view/photographs/sidebar.rhtml +0 -7
  138. data/lib/cortex_reaver/view/projects/form.rhtml +0 -14
  139. data/lib/cortex_reaver/view/projects/list.rhtml +0 -31
  140. data/lib/cortex_reaver/view/projects/show.rhtml +0 -42
  141. data/lib/proto/cortex_reaver.yaml +0 -47
@@ -1,3 +1,22 @@
1
+ h1 a, h2 a, h3 a {
2
+ color: #202020;
3
+ }
4
+
5
+ #main {
6
+ background: #fff;
7
+ }
8
+
9
+ /* Colophon */
10
+ #colophon {
11
+ color: #555;
12
+ }
13
+
14
+ /* Text entries */
15
+ .text-entry h2 {
16
+ margin-bottom: 0;
17
+ padding-bottom: 0;
18
+ }
19
+
1
20
  .text-entry .byline {
2
21
  color: #666;
3
22
  position: relative;
@@ -6,7 +25,6 @@
6
25
  .text-entry .footer {
7
26
  background: #eee;
8
27
  border-bottom: 1px dashed #aaa;
9
- margin-bottom: 1.5em;
10
28
  padding: 2px;
11
29
  }
12
30
 
@@ -0,0 +1,50 @@
1
+ #top .actions {
2
+ top: 30px;
3
+ position: absolute;
4
+ padding: 0;
5
+ margin: 0;
6
+ }
7
+
8
+ #top .actions > li {
9
+ float: left;
10
+ display: block;
11
+ padding: 0;
12
+ margin-right: 8px;
13
+ width: 40px;
14
+ height: 40px;
15
+ }
16
+
17
+ #top .actions > li > a {
18
+ display: block;
19
+ height: 40px;
20
+ overflow: hidden;
21
+ line-height: 200px;
22
+ margin: 0;
23
+ padding: 0;
24
+ color: transparent;
25
+ }
26
+
27
+ #top .actions a.previous {
28
+ background:transparent url(/images/prev_34.png) no-repeat scroll center center;
29
+ }
30
+ #top .actions a.previous:hover {
31
+ background-image: url(/images/prev_34_prelight.png);
32
+ }
33
+ #top .actions a.up {
34
+ background:transparent url(/images/grid_34.png) no-repeat scroll center center;
35
+ }
36
+ #top .actions a.up:hover {
37
+ background-image: url(/images/grid_34_prelight.png);
38
+ }
39
+ #top .actions a.edit {
40
+ background:transparent url(/images/edit_34.png) no-repeat scroll center center;
41
+ }
42
+ #top .actions a.edit:hover {
43
+ background-image: url(/images/edit_34_prelight.png);
44
+ }
45
+ #top .actions a.next {
46
+ background:transparent url(/images/next_34.png) no-repeat scroll center center;
47
+ }
48
+ #top .actions a.next:hover {
49
+ background-image: url(/images/next_34_prelight.png);
50
+ }
@@ -0,0 +1,3 @@
1
+ table.users {
2
+ width: 100%;
3
+ }
@@ -1,34 +1,27 @@
1
1
  // Show the admin box by default if we have a cookie that asks for it.
2
- $(window).load(function() {
2
+ $(document).ready(function() {
3
3
  if(Cookie.get('adminboxopen') == 'true') {
4
- $('#adminbox').show();
4
+ $('.admin.bar').show();
5
5
  }
6
6
  });
7
7
 
8
- $(window).keypress(function(e) {
9
- var code;
10
- if (!e) var e = window.event;
11
- if (e.keyCode) code = e.keyCode;
12
- else if (e.which) code = e.which;
13
- var c = String.fromCharCode(code);
14
- if (c == "x" && e.ctrlKey) {
15
- // Toggle admin tools
16
- var a = $('#adminbox');
17
- a.slideToggle('fast', function() {
18
- if ($('adminbox:visible')) {
19
- // Focus tools
20
- if ($('#admin_login')) $('#admin_login').focus();
21
- } else {
22
- // Unfocus tools
23
- if ($('#admin_login')) $('#admin_login').blur();
24
- }
25
- });
26
- }
8
+ $(document).bind('keydown', {combi:'Alt+Ctrl+a',}, function() {
9
+ // Toggle admin tools
10
+ var a = $('.admin.bar');
11
+ a.slideToggle('fast', function() {
12
+ if ($('.admin.bar:visible')) {
13
+ // Focus tools
14
+ if ($('#admin_login')) $('#admin_login').focus();
15
+ } else {
16
+ // Unfocus tools
17
+ if ($('#admin_login')) $('#admin_login').blur();
18
+ }
19
+ });
27
20
  });
28
21
 
29
22
  // On leaving the page, remember the admin tool state.
30
23
  $(window).unload(function() {
31
- if($('#adminbox').is(':visible')) {
24
+ if($('.admin.bar').is(':visible')) {
32
25
  Cookie.set('adminboxopen', 'true', 14);
33
26
  } else {
34
27
  Cookie.erase('adminboxopen');
@@ -0,0 +1,120 @@
1
+ /**
2
+ * jquery.autotags.js - awesome tag editing
3
+ *
4
+ * Copyright (c) 2009 Kyle Kingsbury (aphyr@aphyr.com)
5
+ *
6
+ * Released under the MIT License:
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ *
9
+ */
10
+
11
+ (function($) {
12
+ $.fn.autotags = function(settings) {
13
+ // Configuration
14
+ var config = {
15
+ cacheLength: 50
16
+ };
17
+ var keys = {
18
+ backspace: 8,
19
+ tab: 9,
20
+ "return": 13,
21
+ "escape": 27,
22
+ comma: 188
23
+ };
24
+
25
+ if (settings) $.extend(config, settings);
26
+
27
+ return this.each(function () {
28
+ // MEAT AND POTATOES AND FUNCTIONS (MINUS THE COMESTIBLES)
29
+
30
+ // Adds a string to the tag list.
31
+ function addTag(tag) {
32
+ var node = document.createElement("li");
33
+ $(node).append('<span>' + tag + '</span><a href="#" title="Remove tag">x</a>');
34
+
35
+ // When clicked, remove the node and save the tags list.
36
+ $(node).find('a').click(function() {
37
+ $(node).remove();
38
+ saveTags();
39
+ })
40
+
41
+ // Add to the list.
42
+ $list.append(node);
43
+ }
44
+
45
+ // Writes the tag list to the original input field.
46
+ function saveTags() {
47
+ $field.val(
48
+ $.map($list.find('li > span'), function(obj) {
49
+ return $(obj).text();
50
+ }).join(',')
51
+ );
52
+ }
53
+
54
+
55
+ // ZOOM ZOOM ZOOM SET UP THE APP!
56
+ // FILL THE DOM WITH USELESS CRAP!
57
+
58
+ // Get original field
59
+ var $field = $(this);
60
+
61
+ // Hide field and append our widget
62
+ $field.hide();
63
+ var $container = $field.after('<div class="tag-editor"></div>').next();
64
+
65
+ // Tag list
66
+ $container.append('<ul></ul>');
67
+ var $list = $container.find('ul');
68
+
69
+ // Input field
70
+ $container.append('<input type="text">');
71
+ var $input = $container.find('input');
72
+
73
+ // Visual clear
74
+ $container.after('<div style="clear: both"></div>');
75
+
76
+ // Add tags from the original field's contents.
77
+ if ($.trim($field.val()) != '') {
78
+ $.each($field.val().split(','), function(i, tag) {
79
+ addTag($.trim(tag));
80
+ });
81
+ saveTags();
82
+ }
83
+
84
+ // Add autocomplete functionality!
85
+ $input.autocomplete(config.url);
86
+
87
+
88
+ // IM CALLING SEXY BACK(YEAH);
89
+ // THOSE OTHER FUNCTIONS DON'T KNOW HOW TO ACT;
90
+
91
+ // Focus input field when any part of the editor is clicked.
92
+ $container.click(function() {
93
+ $input.focus();
94
+ });
95
+
96
+ // Handle keypresses in the input box...
97
+ $input.keydown(function(e, code) {
98
+ code = code || e.keyCode;
99
+ if (code == keys['return'] || code == 188 || code == keys.tab) {
100
+ if ($input.val() != '') {
101
+ // Accept new tag
102
+ var newTag = $input.val();
103
+ $input.val('');
104
+ addTag(newTag);
105
+ saveTags();
106
+
107
+ // Don't submit/leave/add a comma!
108
+ return false;
109
+ }
110
+ } else if (code == keys.backspace && $input.val() == '') {
111
+ // Remove the previous tag
112
+ $list.find("li:last").remove();
113
+ saveTags();
114
+ }
115
+ });
116
+ });
117
+ };
118
+
119
+ // Private methods
120
+ })(jQuery);
@@ -1,142 +1,13 @@
1
1
  /*
2
- * Autocomplete - jQuery plugin 1.0 Beta
2
+ * jQuery Autocomplete plugin 1.1
3
3
  *
4
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
4
+ * Copyright (c) 2009 Jörn Zaefferer
5
5
  *
6
6
  * Dual licensed under the MIT and GPL licenses:
7
7
  * http://www.opensource.org/licenses/mit-license.php
8
8
  * http://www.gnu.org/licenses/gpl.html
9
9
  *
10
- * Revision: $Id: jquery.autocomplete.js 4485 2008-01-20 13:52:47Z joern.zaefferer $
11
- *
12
- */
13
-
14
- /**
15
- * Provide autocomplete for text-inputs or textareas.
16
- *
17
- * Depends on dimensions plugin's offset method for correct positioning of the select box and bgiframe plugin
18
- * to fix IE's problem with selects.
19
- *
20
- * @example $("#input_box").autocomplete("my_autocomplete_backend.php");
21
- * @before <input id="input_box" />
22
- * @desc Autocomplete a text-input with remote data. For small to giant datasets.
23
- *
24
- * When the user starts typing, a request is send to the specified backend ("my_autocomplete_backend.php"),
25
- * with a GET parameter named q that contains the current value of the input box and a paremeter "limit" with
26
- * the value specified for the max option.
27
- *
28
- * A value of "foo" would result in this request url: my_autocomplete_backend.php?q=foo&limit=10
29
- *
30
- * The result must return with one value on each line. The result is presented in the order
31
- * the backend sends it.
32
- *
33
- * @example $("#input_box").autocomplete(["Cologne", "Berlin", "Munich"]);
34
- * @before <input id="input_box" />
35
- * @desc Autcomplete a text-input with local data. For small datasets.
36
- *
37
- * @example $.getJSON("my_backend.php", function(data) {
38
- * $("#input_box").autocomplete(data);
39
- * });
40
- * @before <input id="input_box" />
41
- * @desc Autcomplete a text-input with data received via AJAX. For small to medium sized datasets.
42
- *
43
- * @example $("#mytextarea").autocomplete(["Cologne", "Berlin", "Munich"], {
44
- * multiple: true
45
- * });
46
- * @before <textarea id="mytextarea" />
47
- * @desc Autcomplete a textarea with local data (for small datasets). Once the user chooses one
48
- * value, a separator is appended (by default a comma, see multipleSeparator option) and more values
49
- * are autocompleted.
50
- *
51
- * @name autocomplete
52
- * @cat Plugins/Autocomplete
53
- * @type $
54
- * @param String|Array urlOrData Pass either an URL for remote-autocompletion or an array of data for local auto-completion
55
- * @param Map options Optional settings
56
- * @option String inputClass This class will be added to the input box. Default: "ac_input"
57
- * @option String resultsClass The class for the UL that will contain the result items (result items are LI elements). Default: "ac_results"
58
- * @option String loadingClass The class for the input box while results are being fetched from the server. Default: "ac_loading"
59
- * @option Number minChars The minimum number of characters a user has to type before the autocompleter activates. Default: 1
60
- * @option Number delay The delay in milliseconds the autocompleter waits after a keystroke to activate itself. Default: 400 for remote, 10 for local
61
- * @option Number cacheLength The number of backend query results to store in cache. If set to 1 (the current result), no caching will happen. Do not set below 1. Default: 10
62
- * @option Boolean matchSubset Whether or not the autocompleter can use a cache for more specific queries. This means that all matches of "foot" are a subset of all matches for "foo". Usually this is true, and using this options decreases server load and increases performance. Only useful with cacheLength settings bigger than one, like 10. Default: true
63
- * @option Boolean matchCase Whether or not the comparison is case sensitive. Important only if you use caching. Default: false
64
- * @option Boolean matchContains Whether or not the comparison looks inside (i.e. does "ba" match "foo bar") the search results. Important only if you use caching. Don't mix with autofill. Default: false
65
- * @option Booolean mustMatch If set to true, the autocompleter will only allow results that are presented by the backend. Note that illegal values result in an empty input box. Default: false
66
- * @option Object extraParams Extra parameters for the backend. If you were to specify { bar:4 }, the autocompleter would call my_autocomplete_backend.php?q=foo&bar=4 (assuming the input box contains "foo"). The param can be a function that is called to calculate the param before each request. Default: none
67
- * @option Boolean selectFirst If this is set to true, the first autocomplete value will be automatically selected on tab/return, even if it has not been handpicked by keyboard or mouse action. If there is a handpicked (highlighted) result, that result will take precedence. Default: true
68
- * @option Function formatItem Provides advanced markup for an item. For each row of results, this function will be called. The returned value will be displayed inside an LI element in the results list. Autocompleter will provide 4 parameters: the results row, the position of the row in the list of results (starting at 1), the number of items in the list of results and the search term. Default: none, assumes that a single row contains a single value.
69
- * @option Function formatResult Similar to formatItem, but provides the formatting for the value to be put into the input field. Again three arguments: Data, position (starting with one) and total number of data. Default: none, assumes either plain data to use as result or uses the same value as provided by formatItem.
70
- * @option Boolean multiple Whether to allow more than one autocomplted-value to enter. Default: false
71
- * @option String multipleSeparator Seperator to put between values when using multiple option. Default: ", "
72
- * @option Number width Specify a custom width for the select box. Default: width of the input element
73
- * @option Boolean autoFill Fill the textinput while still selecting a value, replacing the value if more is typed or something else is selected. Default: false
74
- * @option Number max Limit the number of items in the select box. Is also sent as a "limit" parameter with a remote request. Default: 10
75
- * @option Boolean|Function highlight Whether and how to highlight matches in the select box. Set to false to disable. Set to a function to customize. The function gets the value as the first argument and the search term as the second and must return the formatted value. Default: Wraps the search term in a <strong> element
76
- * @option Boolean scroll Whether to scroll when more results than configured via scrollHeight are available. Default: true
77
- * @option Number scrollHeight height of scrolled autocomplete control in pixels
78
- * @option String attachTo The element to attach the autocomplete list to. Useful if used inside a modal window like Thickbox. Default: body -MM
79
- */
80
-
81
- /**
82
- * Handle the result of a search event. Is executed when the user selects a value or a
83
- * programmatic search event is triggered (see search()).
84
- *
85
- * You can add and remove (using unbind("result")) this event at any time.
86
- *
87
- * @example $('input#suggest').result(function(event, data, formatted) {
88
- * $("#result").html( !data ? "No match!" : "Selected: " + formatted);
89
- * });
90
- * @desc Bind a handler to the result event to display the selected value in a #result element.
91
- * The first argument is a generic event object, in this case with type "result".
92
- * The second argument refers to the selected data, which can be a plain string value or an array or object.
93
- * The third argument is the formatted value that is inserted into the input field.
94
- *
95
- * @param Function handler The event handler, gets a default event object as first and
96
- * the selected list item as second argument.
97
- * @name result
98
- * @cat Plugins/Autocomplete
99
- * @type $
100
- */
101
-
102
- /**
103
- * Trigger a search event. See result(Function) for binding to that event.
104
- *
105
- * A search event mimics the same behaviour as when the user selects a value from
106
- * the list of autocomplete items. You can use it to execute anything that does something
107
- * with the selected value, beyond simply putting the value into the input and submitting it.
108
- *
109
- * @example $('input#suggest').search();
110
- * @desc Triggers a search event.
111
- *
112
- * @name search
113
- * @cat Plugins/Autocomplete
114
- * @type $
115
- */
116
-
117
- /**
118
- * Flush (empty) the cache of matched input's autocompleters.
119
- *
120
- * @example $('input#suggest').flushCache();
121
- *
122
- * @name flushCache
123
- * @cat Plugins/Autocomplete
124
- * @type $
125
- */
126
-
127
- /**
128
- * Updates the options for the current autocomplete field. This allows
129
- * you to change things like the URL, max items to display, etc. If you're
130
- * changing the URL, be sure to remember to call the flushCache() method.
131
- *
132
- * @example $('input#suggest').setOptions({
133
- * max: 15
134
- * });
135
- * @desc Changes the maximum number of items to display to 15.
136
- *
137
- * @name setOptions
138
- * @cat Plugins/Autocomplete
139
- * @type $
10
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
140
11
  */
141
12
 
142
13
  ;(function($) {
@@ -154,6 +25,9 @@ $.fn.extend({
154
25
  // if highlight is set to false, replace it with a do-nothing function
155
26
  options.highlight = options.highlight || function(value) { return value; };
156
27
 
28
+ // if the formatMatch option is not specified, then use formatItem for backwards compatibility
29
+ options.formatMatch = options.formatMatch || options.formatItem;
30
+
157
31
  return this.each(function() {
158
32
  new $.Autocompleter(this, options);
159
33
  });
@@ -186,7 +60,8 @@ $.Autocompleter = function(input, options) {
186
60
  ESC: 27,
187
61
  COMMA: 188,
188
62
  PAGEUP: 33,
189
- PAGEDOWN: 34
63
+ PAGEDOWN: 34,
64
+ BACKSPACE: 8
190
65
  };
191
66
 
192
67
  // Create $ object for input element
@@ -202,7 +77,21 @@ $.Autocompleter = function(input, options) {
202
77
  };
203
78
  var select = $.Autocompleter.Select(options, input, selectCurrent, config);
204
79
 
205
- $input.keydown(function(event) {
80
+ var blockSubmit;
81
+
82
+ // prevent form submit in opera when selecting with return key
83
+ $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
84
+ if (blockSubmit) {
85
+ blockSubmit = false;
86
+ return false;
87
+ }
88
+ });
89
+
90
+ // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
91
+ $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
92
+ // a keypress means the input has focus
93
+ // avoids issue where input had focus before the autocomplete was applied
94
+ hasFocus = 1;
206
95
  // track last key pressed
207
96
  lastKeyPressCode = event.keyCode;
208
97
  switch(event.keyCode) {
@@ -247,11 +136,11 @@ $.Autocompleter = function(input, options) {
247
136
  case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
248
137
  case KEY.TAB:
249
138
  case KEY.RETURN:
250
- if( selectCurrent() ){
251
- // make sure to blur off the current field
252
- if( !options.multiple )
253
- $input.blur();
139
+ if( selectCurrent() ) {
140
+ // stop default to prevent a form submit, Opera needs special handling
254
141
  event.preventDefault();
142
+ blockSubmit = true;
143
+ return false;
255
144
  }
256
145
  break;
257
146
 
@@ -264,8 +153,6 @@ $.Autocompleter = function(input, options) {
264
153
  timeout = setTimeout(onChange, options.delay);
265
154
  break;
266
155
  }
267
- }).keypress(function() {
268
- // having fun with opera - remove this binding and Opera submits the form when we select an entry via return
269
156
  }).focus(function(){
270
157
  // track whether the field has focus, we shouldn't process any
271
158
  // results if the field no longer has focus
@@ -309,6 +196,7 @@ $.Autocompleter = function(input, options) {
309
196
  }).bind("unautocomplete", function() {
310
197
  select.unbind();
311
198
  $input.unbind();
199
+ $(input.form).unbind(".autocomplete");
312
200
  });
313
201
 
314
202
 
@@ -323,7 +211,21 @@ $.Autocompleter = function(input, options) {
323
211
  if ( options.multiple ) {
324
212
  var words = trimWords($input.val());
325
213
  if ( words.length > 1 ) {
326
- v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
214
+ var seperator = options.multipleSeparator.length;
215
+ var cursorAt = $(input).selection().start;
216
+ var wordAt, progress = 0;
217
+ $.each(words, function(i, word) {
218
+ progress += word.length;
219
+ if (cursorAt <= progress) {
220
+ wordAt = i;
221
+ return false;
222
+ }
223
+ progress += seperator;
224
+ });
225
+ words[wordAt] = v;
226
+ // TODO this should set the cursor to the right position, but it gets overriden somewhere
227
+ //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
228
+ v = words.join( options.multipleSeparator );
327
229
  }
328
230
  v += options.multipleSeparator;
329
231
  }
@@ -360,34 +262,41 @@ $.Autocompleter = function(input, options) {
360
262
  };
361
263
 
362
264
  function trimWords(value) {
363
- if ( !value ) {
265
+ if (!value)
364
266
  return [""];
365
- }
366
- var words = value.split( $.trim( options.multipleSeparator ) );
367
- var result = [];
368
- $.each(words, function(i, value) {
369
- if ( $.trim(value) )
370
- result[i] = $.trim(value);
267
+ if (!options.multiple)
268
+ return [$.trim(value)];
269
+ return $.map(value.split(options.multipleSeparator), function(word) {
270
+ return $.trim(value).length ? $.trim(word) : null;
371
271
  });
372
- return result;
373
272
  }
374
273
 
375
274
  function lastWord(value) {
376
275
  if ( !options.multiple )
377
276
  return value;
378
277
  var words = trimWords(value);
278
+ if (words.length == 1)
279
+ return words[0];
280
+ var cursorAt = $(input).selection().start;
281
+ if (cursorAt == value.length) {
282
+ words = trimWords(value)
283
+ } else {
284
+ words = trimWords(value.replace(value.substring(cursorAt), ""));
285
+ }
379
286
  return words[words.length - 1];
380
287
  }
381
288
 
382
289
  // fills in the input box w/the first match (assumed to be the best match)
290
+ // q: the term entered
291
+ // sValue: the first matching result
383
292
  function autoFill(q, sValue){
384
293
  // autofill in the complete box w/the first match as long as the user hasn't entered in more data
385
294
  // if the last user key pressed was backspace, don't autofill
386
- if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != 8 ) {
295
+ if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
387
296
  // fill in the value (keep the case the user has typed)
388
297
  $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
389
298
  // select the portion of the value not typed by the user (so the next character will erase)
390
- $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
299
+ $(input).selection(previousValue.length, previousValue.length + sValue.length);
391
300
  }
392
301
  };
393
302
 
@@ -397,6 +306,7 @@ $.Autocompleter = function(input, options) {
397
306
  };
398
307
 
399
308
  function hideResultsNow() {
309
+ var wasVisible = select.visible();
400
310
  select.hide();
401
311
  clearTimeout(timeout);
402
312
  stopLoading();
@@ -405,7 +315,16 @@ $.Autocompleter = function(input, options) {
405
315
  $input.search(
406
316
  function (result){
407
317
  // if no value found, clear the input box
408
- if( !result ) $input.val("");
318
+ if( !result ) {
319
+ if (options.multiple) {
320
+ var words = trimWords($input.val()).slice(0, -1);
321
+ $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
322
+ }
323
+ else {
324
+ $input.val( "" );
325
+ $input.trigger("result", null);
326
+ }
327
+ }
409
328
  }
410
329
  );
411
330
  }
@@ -432,7 +351,9 @@ $.Autocompleter = function(input, options) {
432
351
  // if an AJAX url has been supplied, try loading the data now
433
352
  } else if( (typeof options.url == "string") && (options.url.length > 0) ){
434
353
 
435
- var extraParams = {};
354
+ var extraParams = {
355
+ timestamp: +new Date()
356
+ };
436
357
  $.each(options.extraParams, function(key, param) {
437
358
  extraParams[key] = typeof param == "function" ? param() : param;
438
359
  });
@@ -455,6 +376,8 @@ $.Autocompleter = function(input, options) {
455
376
  }
456
377
  });
457
378
  } else {
379
+ // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
380
+ select.emptyList();
458
381
  failure(term);
459
382
  }
460
383
  };
@@ -497,6 +420,7 @@ $.Autocompleter.defaults = {
497
420
  extraParams: {},
498
421
  selectFirst: true,
499
422
  formatItem: function(row) { return row[0]; },
423
+ formatMatch: null,
500
424
  autoFill: false,
501
425
  width: 0,
502
426
  multiple: false,
@@ -505,8 +429,7 @@ $.Autocompleter.defaults = {
505
429
  return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
506
430
  },
507
431
  scroll: true,
508
- scrollHeight: 180,
509
- attachTo: 'body'
432
+ scrollHeight: 180
510
433
  };
511
434
 
512
435
  $.Autocompleter.Cache = function(options) {
@@ -518,6 +441,9 @@ $.Autocompleter.Cache = function(options) {
518
441
  if (!options.matchCase)
519
442
  s = s.toLowerCase();
520
443
  var i = s.indexOf(sub);
444
+ if (options.matchContains == "word"){
445
+ i = s.toLowerCase().search("\\b" + sub.toLowerCase());
446
+ }
521
447
  if (i == -1) return false;
522
448
  return i == 0 || options.matchContains;
523
449
  };
@@ -550,7 +476,7 @@ $.Autocompleter.Cache = function(options) {
550
476
  // if rawValue is a string, make an array otherwise just reference the array
551
477
  rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
552
478
 
553
- var value = options.formatItem(rawValue, i+1, options.data.length);
479
+ var value = options.formatMatch(rawValue, i+1, options.data.length);
554
480
  if ( value === false )
555
481
  continue;
556
482
 
@@ -666,9 +592,9 @@ $.Autocompleter.Select = function (options, input, select, config) {
666
592
  .hide()
667
593
  .addClass(options.resultsClass)
668
594
  .css("position", "absolute")
669
- .appendTo(options.attachTo);
595
+ .appendTo(document.body);
670
596
 
671
- list = $("<ul>").appendTo(element).mouseover( function(event) {
597
+ list = $("<ul/>").appendTo(element).mouseover( function(event) {
672
598
  if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
673
599
  active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
674
600
  $(target(event)).addClass(CLASSES.ACTIVE);
@@ -676,6 +602,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
676
602
  }).click(function(event) {
677
603
  $(target(event)).addClass(CLASSES.ACTIVE);
678
604
  select();
605
+ // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
679
606
  input.focus();
680
607
  return false;
681
608
  }).mousedown(function() {
@@ -701,7 +628,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
701
628
  }
702
629
 
703
630
  function moveSelect(step) {
704
- listItems.slice(active, active + 1).removeClass();
631
+ listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
705
632
  movePosition(step);
706
633
  var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
707
634
  if(options.scroll) {
@@ -741,7 +668,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
741
668
  var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
742
669
  if ( formatted === false )
743
670
  continue;
744
- var li = $("<li>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_event" : "ac_odd").appendTo(list)[0];
671
+ var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
745
672
  $.data(li, "ac_data", data[i]);
746
673
  }
747
674
  listItems = list.find("li");
@@ -749,7 +676,9 @@ $.Autocompleter.Select = function (options, input, select, config) {
749
676
  listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
750
677
  active = 0;
751
678
  }
752
- list.bgiframe();
679
+ // apply bgiframe if available
680
+ if ( $.fn.bgiframe )
681
+ list.bgiframe();
753
682
  }
754
683
 
755
684
  return {
@@ -781,6 +710,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
781
710
  },
782
711
  hide: function() {
783
712
  element && element.hide();
713
+ listItems && listItems.removeClass(CLASSES.ACTIVE);
784
714
  active = -1;
785
715
  },
786
716
  visible : function() {
@@ -822,28 +752,57 @@ $.Autocompleter.Select = function (options, input, select, config) {
822
752
  var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
823
753
  return selected && selected.length && $.data(selected[0], "ac_data");
824
754
  },
755
+ emptyList: function (){
756
+ list && list.empty();
757
+ },
825
758
  unbind: function() {
826
759
  element && element.remove();
827
760
  }
828
761
  };
829
762
  };
830
763
 
831
- $.Autocompleter.Selection = function(field, start, end) {
832
- if( field.createTextRange ){
833
- var selRange = field.createTextRange();
834
- selRange.collapse(true);
835
- selRange.moveStart("character", start);
836
- selRange.moveEnd("character", end);
837
- selRange.select();
838
- } else if( field.setSelectionRange ){
839
- field.setSelectionRange(start, end);
840
- } else {
841
- if( field.selectionStart ){
842
- field.selectionStart = start;
843
- field.selectionEnd = end;
764
+ $.fn.selection = function(start, end) {
765
+ if (start !== undefined) {
766
+ return this.each(function() {
767
+ if( this.createTextRange ){
768
+ var selRange = this.createTextRange();
769
+ if (end === undefined || start == end) {
770
+ selRange.move("character", start);
771
+ selRange.select();
772
+ } else {
773
+ selRange.collapse(true);
774
+ selRange.moveStart("character", start);
775
+ selRange.moveEnd("character", end);
776
+ selRange.select();
777
+ }
778
+ } else if( this.setSelectionRange ){
779
+ this.setSelectionRange(start, end);
780
+ } else if( this.selectionStart ){
781
+ this.selectionStart = start;
782
+ this.selectionEnd = end;
783
+ }
784
+ });
785
+ }
786
+ var field = this[0];
787
+ if ( field.createTextRange ) {
788
+ var range = document.selection.createRange(),
789
+ orig = field.value,
790
+ teststring = "<->",
791
+ textLength = range.text.length;
792
+ range.text = teststring;
793
+ var caretAt = field.value.indexOf(teststring);
794
+ field.value = orig;
795
+ this.selection(caretAt, caretAt + textLength);
796
+ return {
797
+ start: caretAt,
798
+ end: caretAt + textLength
799
+ }
800
+ } else if( field.selectionStart !== undefined ){
801
+ return {
802
+ start: field.selectionStart,
803
+ end: field.selectionEnd
844
804
  }
845
805
  }
846
- field.focus();
847
806
  };
848
807
 
849
- })(jQuery);
808
+ })(jQuery);