Commit a58a143f152d5a79d2f543e6e017e97fb0e4f69a
Exists in
master
and in
22 other branches
Merge branch 'AI2582-Link_List_Block_Improvements' into rails235
Showing
10 changed files
with
234 additions
and
36 deletions
Show diff stats
app/controllers/box_organizer_controller.rb
| ... | ... | @@ -80,6 +80,22 @@ class BoxOrganizerController < 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 | + path_list = if boxes_holder.is_a?(Environment) && boxes_holder.enabled?('use_portal_community') && boxes_holder.portal_community | |
| 87 | + boxes_holder.portal_community.articles.find(:all, :conditions=>"name ILIKE '%#{search}%' or path ILIKE '%#{search}%'", :limit=>20).map { |content| "/{portal}/"+content.path } | |
| 88 | + elsif boxes_holder.is_a?(Profile) | |
| 89 | + boxes_holder.articles.find(:all, :conditions=>"name ILIKE '%#{search}%' or path ILIKE '%#{search}%'", :limit=>20).map { |content| "/{profile}/"+content.path } | |
| 90 | + else | |
| 91 | + [] | |
| 92 | + end | |
| 93 | + render :json => path_list.to_json | |
| 94 | + else | |
| 95 | + redirect_to "/" | |
| 96 | + end | |
| 97 | + end | |
| 98 | + | |
| 83 | 99 | def save |
| 84 | 100 | @block = boxes_holder.blocks.find(params[:id]) |
| 85 | 101 | @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/models/link_list_block.rb
| ... | ... | @@ -70,6 +70,8 @@ class LinkListBlock < Block |
| 70 | 70 | def expand_address(address) |
| 71 | 71 | add = if owner.respond_to?(:identifier) |
| 72 | 72 | address.gsub('{profile}', owner.identifier) |
| 73 | + elsif owner.is_a?(Environment) && owner.enabled?('use_portal_community') && owner.portal_community | |
| 74 | + address.gsub('{portal}', owner.portal_community.identifier) | |
| 73 | 75 | else |
| 74 | 76 | address |
| 75 | 77 | end | ... | ... |
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, _('Delete'), "#" , :class=>"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, _('Delete'), "#" , :class=>"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 %> | ... | ... |
1.11 KB
| ... | ... | @@ -0,0 +1,39 @@ |
| 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 | + return false; | |
| 27 | + }); | |
| 28 | + | |
| 29 | + jQuery(document).scrollTop(jQuery('#dropable-link-list').scrollTop()); | |
| 30 | +} | |
| 31 | + | |
| 32 | +jQuery(document).ready(function(){ | |
| 33 | + new_link_action(); | |
| 34 | + | |
| 35 | + jQuery("#dropable-link-list").sortable({ | |
| 36 | + revert: true, | |
| 37 | + axis: "y" | |
| 38 | + }); | |
| 39 | +}); | |
| 0 | 40 | \ No newline at end of file | ... | ... |
public/stylesheets/application.css
| ... | ... | @@ -1859,20 +1859,70 @@ 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 | -#edit-link-list-block table { | |
| 1868 | - width: auto; | |
| 1869 | - margin-bottom: 10px; | |
| 1867 | +.link-list-header { | |
| 1868 | + width: 98%; | |
| 1869 | + height: 25px; | |
| 1870 | + padding: 10px 1px 10px 10px; | |
| 1871 | + margin-bottom: 5px; | |
| 1872 | + cursor: pointer; | |
| 1870 | 1873 | } |
| 1871 | -#edit-link-list-block table .cel-address { | |
| 1872 | - width: 220px; | |
| 1874 | +.link-list-header li { | |
| 1875 | + list-style-type: none; | |
| 1876 | + display: inline; | |
| 1877 | + font-weight: bold; | |
| 1878 | + font-size: 14px; | |
| 1879 | + text-align: center; | |
| 1873 | 1880 | } |
| 1874 | -#edit-link-list-block table .cel-address input { | |
| 1875 | - width: 100%; | |
| 1881 | +#dropable-link-list { | |
| 1882 | + padding-left: 23px; | |
| 1883 | + margin-top: -12px; | |
| 1884 | +} | |
| 1885 | +#dropable-link-list li { | |
| 1886 | + list-style-type: none; | |
| 1887 | +} | |
| 1888 | +.link-list-row { | |
| 1889 | + line-height: 25px; | |
| 1890 | + margin-bottom: 5px; | |
| 1891 | + padding: 10px 1px 10px 10px; | |
| 1892 | + cursor: pointer; | |
| 1893 | + width: 97%; | |
| 1894 | +} | |
| 1895 | +.link-list-row:hover { | |
| 1896 | + background: #ddd url(/images/drag-and-drop.png) no-repeat; | |
| 1897 | + background-position: 98% 15px; | |
| 1898 | +} | |
| 1899 | +.link-list-row li { | |
| 1900 | + list-style-type: none; | |
| 1901 | + display: inline; | |
| 1902 | + margin-left: 5px; | |
| 1903 | +} | |
| 1904 | +.link-list-row li div { | |
| 1905 | + float: left; | |
| 1906 | + margin-top: 4px; | |
| 1907 | +} | |
| 1908 | +.link-list-row li a { | |
| 1909 | + line-height: 27px !important; | |
| 1910 | + padding-right: 5px; | |
| 1911 | +} | |
| 1912 | +.link-list-icon { | |
| 1913 | + margin-left: 14px; | |
| 1914 | +} | |
| 1915 | +.link-list-name { | |
| 1916 | + margin-left: 40px; | |
| 1917 | +} | |
| 1918 | +.link-list-address { | |
| 1919 | + margin-left: 90px; | |
| 1920 | +} | |
| 1921 | +.link-list-target { | |
| 1922 | + margin-left: 77px; | |
| 1923 | +} | |
| 1924 | +.new_link_row li { | |
| 1925 | + margin-left: 7px; | |
| 1876 | 1926 | } |
| 1877 | 1927 | #content .link-list-block { |
| 1878 | 1928 | padding: 10px 0px 10px 10px; | ... | ... |
test/functional/environment_design_controller_test.rb
| ... | ... | @@ -379,4 +379,38 @@ class EnvironmentDesignControllerTest < ActionController::TestCase |
| 379 | 379 | end |
| 380 | 380 | end |
| 381 | 381 | |
| 382 | + should 'return a list of paths from portal related to the words used in the query search' do | |
| 383 | + env = Environment.default | |
| 384 | + login_as(create_admin_user(env)) | |
| 385 | + community = fast_create(Community, :environment_id => env) | |
| 386 | + env.portal_community = community | |
| 387 | + env.enable('use_portal_community') | |
| 388 | + env.save | |
| 389 | + @controller.stubs(:boxes_holder).returns(env) | |
| 390 | + article1 = fast_create(Article, :profile_id => community.id, :name => "Some thing") | |
| 391 | + article2 = fast_create(Article, :profile_id => community.id, :name => "Some article") | |
| 392 | + article3 = fast_create(Article, :profile_id => community.id, :name => "Not an article") | |
| 393 | + | |
| 394 | + xhr :get, :search_autocomplete, :query => 'Some' | |
| 395 | + | |
| 396 | + json_response = ActiveSupport::JSON.decode(@response.body) | |
| 397 | + | |
| 398 | + assert_response :success | |
| 399 | + assert_equal json_response.include?("/{portal}/"+article1.path), true | |
| 400 | + assert_equal json_response.include?("/{portal}/"+article2.path), true | |
| 401 | + assert_equal json_response.include?("/{portal}/"+article3.path), false | |
| 402 | + end | |
| 403 | + | |
| 404 | + should 'return empty if portal not configured' do | |
| 405 | + env = Environment.default | |
| 406 | + login_as(create_admin_user(env)) | |
| 407 | + | |
| 408 | + xhr :get, :search_autocomplete, :query => 'Some' | |
| 409 | + | |
| 410 | + json_response = ActiveSupport::JSON.decode(@response.body) | |
| 411 | + | |
| 412 | + assert_response :success | |
| 413 | + assert_equal json_response, [] | |
| 414 | + end | |
| 415 | + | |
| 382 | 416 | end | ... | ... |
test/functional/profile_design_controller_test.rb
| ... | ... | @@ -320,6 +320,20 @@ class ProfileDesignControllerTest < 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 | + | |
| 330 | + json_response = ActiveSupport::JSON.decode(@response.body) | |
| 331 | + | |
| 332 | + assert_response :success | |
| 333 | + assert_equal json_response.include?("/{profile}/"+article1.path), true | |
| 334 | + assert_equal json_response.include?("/{profile}/"+article2.path), true | |
| 335 | + assert_equal json_response.include?("/{profile}/"+article3.path), false | |
| 336 | + end | |
| 323 | 337 | |
| 324 | 338 | ###################################################### |
| 325 | 339 | # END - tests for BoxOrganizerController features | ... | ... |
test/unit/link_list_block_test.rb
| ... | ... | @@ -39,6 +39,32 @@ class LinkListBlockTest < ActiveSupport::TestCase |
| 39 | 39 | assert_tag_in_string l.content, :tag => 'a', :attributes => {:href => '/test_profile/address'} |
| 40 | 40 | end |
| 41 | 41 | |
| 42 | + should 'replace {portal} with environment portal identifier' do | |
| 43 | + env = Environment.default | |
| 44 | + env.enable('use_portal_community') | |
| 45 | + portal = fast_create(Community, :identifier => 'portal-community', :environment_id => env.id) | |
| 46 | + env.portal_community = portal | |
| 47 | + env.save | |
| 48 | + | |
| 49 | + stubs(:environment).returns(env) | |
| 50 | + l = LinkListBlock.new(:links => [{:name => 'categ', :address => '/{portal}/address'}]) | |
| 51 | + l.stubs(:owner).returns(env) | |
| 52 | + assert_tag_in_string l.content, :tag => 'a', :attributes => {:href => '/portal-community/address'} | |
| 53 | + end | |
| 54 | + | |
| 55 | + should 'not change address if no {portal} there' do | |
| 56 | + env = Environment.default | |
| 57 | + env.enable('use_portal_community') | |
| 58 | + portal = fast_create(Community, :identifier => 'portal-community', :environment_id => env.id) | |
| 59 | + env.portal_community = portal | |
| 60 | + env.save | |
| 61 | + | |
| 62 | + stubs(:environment).returns(env) | |
| 63 | + l = LinkListBlock.new(:links => [{:name => 'categ', :address => '/address'}]) | |
| 64 | + l.stubs(:owner).returns(env) | |
| 65 | + assert_tag_in_string l.content, :tag => 'a', :attributes => {:href => '/address'} | |
| 66 | + end | |
| 67 | + | |
| 42 | 68 | should 'display options for icons' do |
| 43 | 69 | l = LinkListBlock.new |
| 44 | 70 | l.icons_options.each do |option| | ... | ... |