Commit b15b9498d25805e93c9dc8004143f89766932534

Authored by Fabio Teixeira
1 parent 79818886

Link_List_Block_Improvements: Add Drag and Drop and auto-complete to LinkListBlock

(ActionItem2582)

- Changed link list html structure from table to ul/li
- Added image that indicates draggable area
- Added Drag and Drop javascript
- Added button that delete the link
- Added auto complete to Address field
- Corrected syntax error on token_helper

Signed-off-by: David Carlos <ddavidcarlos1392@gmail.com>
Signed-off-by: Fabio Teixeira <fabio1079@gmail.com>
Signed-off-by: Gustavo Jaruga <darksshades@gmail.com>
Signed-off-by: Luciano Prestes <lucianopcbr@gmail.com>
Signed-off-by: Matheus Faria <matheus.sousa.faria@gmail.com>
app/controllers/box_organizer_controller.rb
... ... @@ -80,6 +80,18 @@ class BoxOrganizerController &lt; ApplicationController
80 80 render :action => 'edit', :layout => false
81 81 end
82 82  
  83 + def search_autocomplete
  84 + if request.xhr? and params[:query]
  85 + search = params[:query]
  86 + articles = @profile.articles.find(:all, :conditions=>"name ILIKE '%#{search}%' or path ILIKE '%#{search}%'", :limit=>20)
  87 + path_list = articles.map { |content| content.path }
  88 +
  89 + render :json => path_list.to_json
  90 + else
  91 + redirect_to "/"
  92 + end
  93 + end
  94 +
83 95 def save
84 96 @block = boxes_holder.blocks.find(params[:id])
85 97 @block.update_attributes(params[:block])
... ...
app/helpers/token_helper.rb
... ... @@ -27,7 +27,7 @@ module TokenHelper
27 27 hintText: #{options[:hint_text].to_json},
28 28 noResultsText: #{options[:no_results_text].to_json},
29 29 searchingText: #{options[:searching_text].to_json},
30   - searchDelay: #{options[:serach_delay].to_json},
  30 + searchDelay: #{options[:search_delay].to_json},
31 31 preventDuplicates: #{options[:prevent_duplicates].to_json},
32 32 backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
33 33 queryParam: #{name.to_json},
... ...
app/views/box_organizer/_link_list_block.rhtml
  1 +<%= javascript_include_tag "edit-link-list.js" %>
  2 +
1 3 <strong><%= _('Links') %></strong>
2 4 <div id='edit-link-list-block'>
3   -<table id='links' class='noborder'>
4   - <tr>
5   - <th><%= _('Icon') %></th>
6   - <th><%= _('Name') %></th>
7   - <th><%= _('Address') %></th>
8   - <th><%= _('Title') %></th>
9   - <th><%= _('Target') %></th>
10   - </tr>
11   - <% for link in @block.links do %>
12   - <tr>
13   - <td><%= icon_selector(link['icon']) %></td>
14   - <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td>
15   - <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td>
16   - <td><%= text_field_tag 'block[links][][title]', link[:title], :class => 'link-title' %></td>
17   - <td><%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %></td>
18   - </tr>
19   - <% end %>
20   -</table>
  5 + <ul class='link-list-header'>
  6 + <li class='link-list-icon'><%= _('Icon') %></li>
  7 + <li class='link-list-name'><%= _('Name') %></li>
  8 + <li class='link-list-address'><%= _('Address') %></li>
  9 + <li class='link-list-target'><%= _('Target') %></li>
  10 + </ul>
  11 + <ul id="dropable-link-list">
  12 + <% for link in @block.links do %>
  13 + <li>
  14 + <ul class="link-list-row">
  15 + <li>
  16 + <%= icon_selector(link['icon']) %>
  17 + </li>
  18 + <li>
  19 + <%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %>
  20 + </li>
  21 + <li>
  22 + <%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %>
  23 + </li>
  24 + <li>
  25 + <%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %>
  26 + </li>
  27 + <li>
  28 + <%= button_without_text("", _('Delete'), "#" , :class=>"icon-delete delete-link-list-row") %>
  29 + </li>
  30 + </ul>
  31 + </li>
  32 + <% end %>
  33 + </ul>
  34 + <input type="hidden" id="page_url" value="<%=url_for(:action=>'search_autocomplete')%>" />
21 35 </div>
22 36  
23 37 <%= link_to_function(_('New link'), nil, :class => 'button icon-add with-text') do |page|
24   - page.insert_html :bottom, 'links', content_tag('tr',
25   - content_tag('td', icon_selector('ok')) +
26   - content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
27   - content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') +
28   - content_tag('td', text_field_tag('block[links][][title]', '', :class => 'link-title')) +
29   - content_tag('td', select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, '_self')))
  38 + page.insert_html :bottom, 'dropable-link-list', content_tag('li',
  39 + content_tag('ul',
  40 + content_tag('li', icon_selector('ok')) +
  41 + content_tag('li', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
  42 + content_tag('li', text_field_tag('block[links][][address]', nil, :class => 'link-address')) +
  43 + content_tag('li', select_tag('block[links][][target]',
  44 + options_for_select(LinkListBlock::TARGET_OPTIONS, '_self'))) +
  45 + content_tag('li', button_without_text("", _('Delete'), "#" , :class=>"icon-delete delete-link-list-row")),
  46 + :class=>"link-list-row new_link_row")
30 47 ) +
31   - javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")
  48 + javascript_tag("new_link_action()")
32 49 end %>
... ...
public/images/drag-and-drop.png 0 → 100644

1.11 KB

public/javascripts/edit-link-list.js 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +function send_ajax(source_url) {
  2 + jQuery(".link-address").autocomplete({
  3 + source : function(request, response){
  4 + jQuery.ajax({
  5 + type: "GET",
  6 + url: source_url,
  7 + data: {query: request.term},
  8 + success: function(result){
  9 + response(result);
  10 + },
  11 + error: function(ajax, stat, errorThrown) {
  12 + console.log('Link not found : ' + errorThrown);
  13 + }
  14 + });
  15 + },
  16 +
  17 + minLength: 3
  18 + });
  19 +}
  20 +
  21 +function new_link_action(){
  22 + send_ajax(jQuery("#page_url").val());
  23 +
  24 + jQuery(".delete-link-list-row").click(function(){
  25 + jQuery(this).parent().parent().remove();
  26 + });
  27 +
  28 + jQuery(".link-address").blur(function(){
  29 + var value = jQuery(this).val();
  30 + var search = /(^$)|(^\/$)|(http|www).*|.*\{profile\}.*|.*(\.com|\.org|\.net|\.edu|\.gov|\.info|\.eu)/;
  31 +
  32 + if( !search.test(value) ) {
  33 + value = "/{profile}/"+value;
  34 + jQuery(this).val(value);
  35 + }
  36 + });
  37 +
  38 + jQuery(document).scrollTop(jQuery('#dropable-link-list').scrollTop());
  39 +}
  40 +
  41 +jQuery(document).ready(function(){
  42 + new_link_action();
  43 +
  44 + jQuery("#dropable-link-list").sortable({
  45 + revert: true,
  46 + axis: "y"
  47 + });
  48 +});
0 49 \ No newline at end of file
... ...
public/stylesheets/application.css
... ... @@ -1859,21 +1859,85 @@ a.button.disabled, input.disabled {
1859 1859 text-decoration: none;
1860 1860 }
1861 1861 /* ==> blocks/link-list-block.css <<= */
1862   -
1863 1862 #edit-link-list-block {
1864   - width: 820px;
  1863 + width: 620px;
  1864 + position: relative;
  1865 + left: -24px;
1865 1866 }
1866 1867  
1867   -#edit-link-list-block table {
1868   - width: auto;
1869   - margin-bottom: 10px;
  1868 +.link-list-header {
  1869 + width: 98%;
  1870 + height: 25px;
  1871 + padding: 10px 1px 10px 10px;
  1872 + margin-bottom: 5px;
  1873 + cursor: pointer;
1870 1874 }
1871   -#edit-link-list-block table .cel-address {
1872   - width: 220px;
  1875 +
  1876 +#dropable-link-list {
  1877 + padding-left: 23px;
  1878 + margin-top: -12px;
1873 1879 }
1874   -#edit-link-list-block table .cel-address input {
1875   - width: 100%;
  1880 +
  1881 +#dropable-link-list li {
  1882 + list-style-type: none;
  1883 +}
  1884 +
  1885 +.link-list-row {
  1886 + line-height: 25px;
  1887 + margin-bottom: 5px;
  1888 + padding: 10px 1px 10px 10px;
  1889 + cursor: pointer;
  1890 + width: 90%;
  1891 +}
  1892 +.link-list-row:hover {
  1893 + background: #aaa url(/images/drag-and-drop.png) no-repeat;
  1894 + background-position: 98% 15px;
  1895 +}
  1896 +
  1897 +.link-list-row li {
  1898 + list-style-type: none;
  1899 + display: inline;
  1900 + margin-left: 5px;
1876 1901 }
  1902 +
  1903 +.link-list-row li div {
  1904 + float: left;
  1905 + margin-top: 4px;
  1906 +}
  1907 +
  1908 +.link-list-row li a {
  1909 + line-height: 27px !important;
  1910 + padding-right: 5px;
  1911 +}
  1912 +
  1913 +.link-list-header li {
  1914 + list-style-type: none;
  1915 + display: inline;
  1916 + font-weight: bold;
  1917 + font-size: 14px;
  1918 + text-align: center;
  1919 +}
  1920 +
  1921 +.link-list-icon {
  1922 + margin-left: 14px;
  1923 +}
  1924 +
  1925 +.link-list-name {
  1926 + margin-left: 40px;
  1927 +}
  1928 +
  1929 +.link-list-address {
  1930 + margin-left: 90px;
  1931 +}
  1932 +
  1933 +.link-list-target {
  1934 + margin-left: 77px;
  1935 +}
  1936 +
  1937 +.new_link_row li {
  1938 + margin-left: 7px;
  1939 +}
  1940 +
1877 1941 #content .link-list-block {
1878 1942 padding: 10px 0px 10px 10px;
1879 1943 }
... ...
test/functional/profile_design_controller_test.rb
... ... @@ -320,6 +320,17 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
320 320 assert_tag :input, :attributes => { :type => 'radio', :value => 'except_home_page'}
321 321 end
322 322  
  323 + should 'return a list of paths related to the words used in the query search' do
  324 + article1 = fast_create(Article, :profile_id => @profile.id, :name => "Some thing")
  325 + article2 = fast_create(Article, :profile_id => @profile.id, :name => "Some article")
  326 + article3 = fast_create(Article, :profile_id => @profile.id, :name => "Not an article")
  327 +
  328 + xhr :get, :search_autocomplete, :profile => 'designtestuser' , :query => 'Some'
  329 + assert_response :success
  330 + assert_equal @response.body.include?(article1.path), true
  331 + assert_equal @response.body.include?(article2.path), true
  332 + assert_equal @response.body.include?(article3.path), false
  333 + end
323 334  
324 335 ######################################################
325 336 # END - tests for BoxOrganizerController features
... ...