add display_type configuration to external tools

this setting should allow tools to choose how they are displayed
in the canvas interface. the new full width display removes the
canvas sidebars, footer, and breadcrumbs.

test plan:
 - install a tool with course_navigation and account_navigation
   extensions.
 - make sure the tool displays normally without a display_type
   configuration.
 - use a console to set display_type = 'full_width' in a tool's
   course_navigation settings.
 - the tool should display as a "full width" tool when viewed
   by the course navigation link. full width means without the
   left or right side bar, without breadcrumbs, and without a
   footer. the canvas header should still be displayed.
 - the tool should display normally when viewed by the account
   navigation link.
 - use the console to set the display_type = 'full_width' in the
   tool's top level settings.
 - tool tool should now display full width using the account
   navigation link.

Change-Id: Idc19c0c96031bd80a45ce984241c23e4ce1efe78
Reviewed-on: https://gerrit.instructure.com/35160
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brad Humphrey <brad@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Jon Willesen <jonw@instructure.com>
This commit is contained in:
Jon Willesen 2014-05-14 11:11:51 -06:00
parent dbb7b52e50
commit 79f84cb830
9 changed files with 134 additions and 37 deletions

View File

@ -27,6 +27,12 @@ class ExternalToolsController < ApplicationController
REDIS_PREFIX = 'external_tool:sessionless_launch:' REDIS_PREFIX = 'external_tool:sessionless_launch:'
TOOL_DISPLAY_TEMPLATES = {
'full_width' => 'external_tools/full_width',
'in_context' => 'external_tools/tool_show',
'default' => 'external_tools/tool_show',
}
# @API List external tools # @API List external tools
# Returns the paginated list of external tools for the current context. # Returns the paginated list of external tools for the current context.
# See the get request docs for a single tool for a list of properties on an external tool. # See the get request docs for a single tool for a list of properties on an external tool.
@ -296,7 +302,7 @@ class ExternalToolsController < ApplicationController
find_tool(params[:id], selection_type) find_tool(params[:id], selection_type)
@active_tab = @tool.asset_string if @tool @active_tab = @tool.asset_string if @tool
@show_embedded_chat = false if @tool.try(:tool_id) == 'chat' @show_embedded_chat = false if @tool.try(:tool_id) == 'chat'
render_tool(selection_type) render tool_launch(@tool, selection_type) if @tool
add_crumb(@context.name, named_context_url(@context, :context_url)) add_crumb(@context.name, named_context_url(@context, :context_url))
end end
end end
@ -314,7 +320,7 @@ class ExternalToolsController < ApplicationController
@tool_launch_type = 'self' @tool_launch_type = 'self'
find_tool(params[:external_tool_id], selection_type) find_tool(params[:external_tool_id], selection_type)
render_tool(selection_type) render tool_launch(@tool, selection_type) if @tool
end end
def find_tool(id, selection_type) def find_tool(id, selection_type)
@ -330,15 +336,13 @@ class ExternalToolsController < ApplicationController
redirect_to named_context_url(@context, :context_url) redirect_to named_context_url(@context, :context_url)
end end
end end
protected :find_tool protected :find_tool
def render_tool(selection_type) def tool_launch(tool, selection_type)
return unless @tool @resource_title = tool.label_for(selection_type.to_sym)
@resource_title = @tool.label_for(selection_type.to_sym)
@return_url ||= url_for(@context) @return_url ||= url_for(@context)
adapter = Lti::LtiOutboundAdapter.new(@tool, @current_user, @context) adapter = Lti::LtiOutboundAdapter.new(tool, @current_user, @context)
adapter.prepare_tool_launch(@return_url, resource_type: selection_type, selected_html: params[:selection]) adapter.prepare_tool_launch(@return_url, resource_type: selection_type, selected_html: params[:selection])
if selection_type == 'homework_submission' if selection_type == 'homework_submission'
@assignment = @context.assignments.active.find(params[:assignment_id]) @assignment = @context.assignments.active.find(params[:assignment_id])
@ -350,13 +354,19 @@ class ExternalToolsController < ApplicationController
@resource_url = adapter.launch_url @resource_url = adapter.launch_url
resource_uri = URI.parse @resource_url resource_uri = URI.parse @resource_url
@tool_id = @tool.tool_id || resource_uri.host || 'unknown' @tool_id = tool.tool_id || resource_uri.host || 'unknown'
@tool_path = (resource_uri.path.empty? ? "/" : resource_uri.path) @tool_path = (resource_uri.path.empty? ? "/" : resource_uri.path)
render :template => 'external_tools/tool_show' return :template => find_display_type_template(tool, selection_type)
end end
protected :tool_launch
def find_display_type_template(tool, selection_type)
TOOL_DISPLAY_TEMPLATES[tool.display_type(selection_type)] ||
TOOL_DISPLAY_TEMPLATES['default']
end
protected :find_display_type_template
protected :render_tool
# @API Create an external tool # @API Create an external tool
# Create an external tool in the specified course/account. # Create an external tool in the specified course/account.

View File

@ -262,6 +262,10 @@ class ContextExternalTool < ActiveRecord::Base
write_attribute(:shared_secret, val) unless val.blank? write_attribute(:shared_secret, val) unless val.blank?
end end
def display_type(extension_type)
extension_setting(extension_type, :display_type) || 'in_context'
end
def extension_setting(type, property = nil) def extension_setting(type, property = nil)
type = type.to_sym type = type.to_sym
return settings[type] unless property && settings[type] return settings[type] unless property && settings[type]
@ -583,6 +587,7 @@ class ContextExternalTool < ActiveRecord::Base
settings[setting][:url] = hash[:url] if hash[:url] settings[setting][:url] = hash[:url] if hash[:url]
settings[setting][:text] = hash[:text] if hash[:text] settings[setting][:text] = hash[:text] if hash[:text]
settings[setting][:display_type] = hash[:display_type] if hash[:display_type]
settings[setting][:custom_fields] = hash[:custom_fields] if hash[:custom_fields] settings[setting][:custom_fields] = hash[:custom_fields] if hash[:custom_fields]
settings[setting][:enabled] = Canvas::Plugin.value_to_boolean(hash[:enabled]) if hash.has_key?(:enabled) settings[setting][:enabled] = Canvas::Plugin.value_to_boolean(hash[:enabled]) if hash.has_key?(:enabled)
keys.each { |key| settings[setting][key] = hash[key] if hash.has_key?(key) } keys.each { |key| settings[setting][key] = hash[key] if hash.has_key?(key) }

View File

@ -0,0 +1,7 @@
#footer {
display: none;
}
#main {
margin: 0;
}

View File

@ -0,0 +1,29 @@
<form action="<%= @resource_url %>"
class="hide"
method="POST" target="tool_content"
id="tool_form"
data-tool-launch-type="<%= @tool_launch_type %>"
data-tool-id="<%= @tool_id %>"
data-tool-path="<%= @tool_path %>">
<% @tool_settings.each do |key, value| %>
<%= hidden_field_tag key, value %>
<% end %>
<% if @tag.try(:new_tab) %>
<div style="margin-bottom: 20px;">
<div class="load_tab">
<%= t :new_tab, "This tool needs to be loaded in a new browser window" %>
<div style="margin: 10px 0;">
<button class="btn" type="submit" data-expired_message="<%= t :new_tab_expired, "The session for this tool has expired. Please reload the page to access the tool again" %>"><%= t :load_tool_new_tab_button, "Load %{tool} in a new window", :tool => @tool.name %></button>
</div>
</div>
<div class="tab_loaded" style="display: none;">
<%= t :new_tab_loaded, "This tool was successfully loaded in a new browser window. Reload the page to access the tool again." %>
</div>
</div>
<% else %>
<button class="btn" type="submit"><%= t :load_tool_button, "Load %{tool}", :tool => @resource_title %></button>
<% end %>
</form>
<%= iframe("about:blank", :name => 'tool_content', :id => 'tool_content', :width => '100%', :height => '400') %>

View File

@ -0,0 +1,12 @@
<% content_for :page_title do %><%= @resource_title %><% end %>
<%
@show_left_side = false
@body_classes << 'full-width'
crumbs.clear
%>
<% js_bundle 'legacy/external_tools_tool_show' %>
<% jammit_css :external_tool_full_width %>
<%= render partial: 'external_tools/tool_post_iframe' %>

View File

@ -26,33 +26,8 @@
</div> </div>
<% end %> <% end %>
<form action="<%= @resource_url %>" <%= render :partial => 'external_tools/tool_post_iframe' %>
class="hide"
method="POST" target=tool_content
id="tool_form"
data-tool-launch-type="<%= @tool_launch_type %>"
data-tool-id="<%= @tool_id %>"
data-tool-path="<%= @tool_path %>">
<% @tool_settings.each do |key, value| %>
<%= hidden_field_tag key, value %>
<% end %>
<% if @tag.try(:new_tab) %>
<div style="margin-bottom: 20px;">
<div class="load_tab">
<%= t :new_tab, "This tool needs to be loaded in a new browser window" %>
<div style="margin: 10px 0;">
<button class="btn" type="submit" data-expired_message="<%= t :new_tab_expired, "The session for this tool has expired. Please reload the page to access the tool again" %>"><%= t :load_tool_new_tab_button, "Load %{tool} in a new window", :tool => @tool.name %></button>
</div>
</div>
<div class="tab_loaded" style="display: none;">
<%= t :new_tab_loaded, "This tool was successfully loaded in a new browser window. Reload the page to access the tool again." %>
</div>
</div>
<% else %>
<button class="btn" type="submit"><%= t :load_tool_button, "Load %{tool}", :tool => @resource_title %></button>
<% end %>
</form>
<%= iframe("about:blank", :name => 'tool_content', :id => 'tool_content', :width => '100%', :height => '400') %>
<% if @tag %> <% if @tag %>
<% if @tag.context.is_a?(Assignment) && (can_do(@tag.context, @current_user, :grade) || can_do(@tag.context.context, @current_user, :manage_assignments)) %> <% if @tag.context.is_a?(Assignment) && (can_do(@tag.context, @current_user, :grade) || can_do(@tag.context.context, @current_user, :manage_assignments)) %>
<% content_for :right_side do %> <% content_for :right_side do %>

View File

@ -188,5 +188,7 @@ stylesheets:
- public/stylesheets/compiled/locale.css - public/stylesheets/compiled/locale.css
mobile_auth: mobile_auth:
- public/stylesheets/compiled/mobile_auth.css - public/stylesheets/compiled/mobile_auth.css
external_tool_full_width:
- public/stylesheets/compiled/external_tools/full_width.css
<%= plugin_assets.anchors_yml %> <%= plugin_assets.anchors_yml %>

View File

@ -510,6 +510,28 @@ describe ContextExternalTool do
tool.resource_selection.should_not == nil tool.resource_selection.should_not == nil
tool.editor_button.should_not == nil tool.editor_button.should_not == nil
end end
describe "display_type" do
it "should be 'in_context' by default" do
tool.display_type(:course_navigation).should == 'in_context'
tool.course_navigation = {enabled: true}
tool.save!
tool.display_type(:course_navigation).should == 'in_context'
end
it "should be configurable by a property" do
tool.course_navigation = { enabled: true }
tool.settings[:display_type] = "custom_display_type"
tool.save!
tool.display_type(:course_navigation).should == 'custom_display_type'
end
it "should be configurable in extension" do
tool.course_navigation = {display_type: 'other_display_type'}
tool.save!
tool.display_type(:course_navigation).should == 'other_display_type'
end
end
end end
describe "change_domain" do describe "change_domain" do

View File

@ -725,6 +725,41 @@ describe "external tools" do
assert_flash_error_message(/couldn't find valid settings/i) assert_flash_error_message(/couldn't find valid settings/i)
end end
describe "display type" do
before do
@tool.course_navigation = {}
@tool.save!
end
it "defaults to normal display type" do
get "/courses/#{@course.id}/external_tools/#{@tool.id}"
f('#footer').should be_displayed
f('#left-side').should_not be_nil
f('#breadcrumbs').should_not be_nil
f('body').attribute('class').should_not include('full-width')
end
it "shows full width if top level property specified" do
@tool.settings[:display_type] = "full_width"
@tool.save!
get "/courses/#{@course.id}/external_tools/#{@tool.id}"
f('#footer').should_not be_displayed
f('#left-side').should be_nil
f('#breadcrumbs').should be_nil
f('body').attribute('class').should include('full-width')
end
it "shows full width if extension property specified" do
@tool.course_navigation[:display_type] = "full_width"
@tool.save!
get "/courses/#{@course.id}/external_tools/#{@tool.id}"
f('#footer').should_not be_displayed
f('#left-side').should be_nil
f('#breadcrumbs').should be_nil
f('body').attribute('class').should include('full-width')
end
end
end end
private private