Commit d2b622cc by marjev Committed by Martyn James

Bugfix for edit not working on solutions + bugfixes for problems noticed by Xavier

parent 8b8da417
......@@ -4,26 +4,13 @@
# Imports ###########################################################
import pkg_resources
#import logging
import textwrap
#import json
#import webob
#from lxml import etree
#from xml.etree import ElementTree as ET
from xblock.core import XBlock
from xblock.fields import Scope, String, Integer
from xblock.fragment import Fragment
# from StringIO import StringIO
from .utils import render_template, AttrDict, load_resource
# Globals ###########################################################
#log = logging.getLogger(__name__)
from .utils import loader, AttrDict
# Classes ###########################################################
......@@ -70,9 +57,9 @@ class GoogleCalendarBlock(XBlock):
"self": self,
"iframe": iframe
})
fragment.add_content(render_template('/templates/html/google_calendar.html', context))
fragment.add_css(load_resource('public/css/google_calendar.css'))
fragment.add_javascript(load_resource('public/js/google_calendar.js'))
fragment.add_content(loader.render_template('/templates/html/google_calendar.html', context))
fragment.add_css(loader.load_unicode('public/css/google_calendar.css'))
fragment.add_javascript(loader.load_unicode('public/js/google_calendar.js'))
fragment.initialize_js('GoogleCalendarBlock')
......@@ -83,17 +70,14 @@ class GoogleCalendarBlock(XBlock):
Editing view in Studio
"""
fragment = Fragment()
fragment.add_content(render_template('/templates/html/google_calendar_edit.html', {
'self': self
}))
fragment.add_javascript(load_resource('public/js/google_calendar_edit.js'))
defaults = {
fragment.add_content(loader.render_template('/templates/html/google_calendar_edit.html', {
'self': self,
'defaultName': self.fields['display_name']._default,
'defaultID': self.fields['calendar_id']._default
}
}))
fragment.add_javascript(loader.load_unicode('public/js/google_calendar_edit.js'))
fragment.initialize_js('GoogleCalendarEditBlock', defaults)
fragment.initialize_js('GoogleCalendarEditBlock')
return fragment
......@@ -116,3 +100,10 @@ class GoogleCalendarBlock(XBlock):
return {
'result': 'success',
}
@staticmethod
def workbench_scenarios():
"""
A canned scenario for display in the workbench.
"""
return [("Google Calendar scenario", "<vertical_demo><google-calendar/></vertical_demo>")]
......@@ -4,27 +4,14 @@
# Imports ###########################################################
import pkg_resources
#import logging
import textwrap
#import json
#import webob
#from lxml import etree
#from xml.etree import ElementTree as ET
import requests
from xblock.core import XBlock
from xblock.fields import Scope, String
from xblock.fragment import Fragment
# from StringIO import StringIO
from .utils import render_template, AttrDict, load_resource
# Globals ###########################################################
#log = logging.getLogger(__name__)
from .utils import loader, AttrDict
# Classes ###########################################################
......@@ -64,9 +51,9 @@ class GoogleDocumentBlock(XBlock):
context.update({
"self": self,
})
fragment.add_content(render_template('/templates/html/google_docs.html', context))
fragment.add_css(load_resource('public/css/google_docs.css'))
fragment.add_javascript(load_resource('public/js/google_docs.js'))
fragment.add_content(loader.render_template('/templates/html/google_docs.html', context))
fragment.add_css(loader.load_unicode('public/css/google_docs.css'))
fragment.add_javascript(loader.load_unicode('public/js/google_docs.js'))
fragment.initialize_js('GoogleDocumentBlock')
......@@ -77,12 +64,13 @@ class GoogleDocumentBlock(XBlock):
Editing view in Studio
"""
fragment = Fragment()
fragment.add_content(render_template('/templates/html/google_docs_edit.html', {
fragment.add_content(loader.render_template('/templates/html/google_docs_edit.html', {
'self': self,
'defaultName': self.fields['display_name']._default
}))
fragment.add_javascript(load_resource('public/js/google_docs_edit.js'))
fragment.add_javascript(loader.load_unicode('public/js/google_docs_edit.js'))
fragment.initialize_js('GoogleDocumentEditBlock', {'defaultName': self.fields['display_name']._default})
fragment.initialize_js('GoogleDocumentEditBlock')
return fragment
......@@ -97,18 +85,13 @@ class GoogleDocumentBlock(XBlock):
}
@XBlock.json_handler
def iframe_loaded(self, iframe_data, suffix=''):
self.runtime.publish(self, 'iframe.loaded', iframe_data)
return {
'result': 'success',
}
@XBlock.json_handler
def image_loaded(self, image_data, suffix=''):
def document_loaded(self, data, suffix=''):
try:
event_name = data.pop('eventName')
except KeyError as e:
return {'result': 'error', 'message': 'Missing eventName in JSON data'}
self.runtime.publish(self, 'image.loaded', image_data)
self.runtime.publish(self, event_name, data)
return {
'result': 'success',
......@@ -127,3 +110,10 @@ class GoogleDocumentBlock(XBlock):
return {
'status_code': r.status_code,
}
@staticmethod
def workbench_scenarios():
"""
A canned scenario for display in the workbench.
"""
return [("Google Docs scenario", "<vertical_demo><google-document/></vertical_demo>")]
......@@ -13,7 +13,7 @@
height: 100%;
}
#validation_alert{
.user-inputs-and-validation .validation_alert{
width: 100%;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
......@@ -26,14 +26,19 @@
max-height: 200px;
}
.alert_icon{
.user-inputs-and-validation .validation_alert.covered {
display: none;
visibility: hidden;
}
.user-inputs-and-validation .validation_alert .alert_icon{
position: absolute;
top: 35%;
font-size: 200%;
left: 3%;
}
.alert_icon:before{
.user-inputs-and-validation .validation_alert .alert_icon:before{
font-family: "FontAwesome";
content: "\f071";
display: inline-block;
......@@ -43,69 +48,51 @@
width: 0;
}
.alert_header {
.user-inputs-and-validation .validation_alert .alert_header {
width: 85%;
margin: 0 5% 0 10%;
}
.alert_title {
.user-inputs-and-validation .validation_alert .alert_header .alert_title {
width: auto;
color: white;
}
.alert_message {
.user-inputs-and-validation .validation_alert .alert_header .alert_message {
font-size: 80%;
color: darkgray;
}
[class^="icon"] {
.user-inputs-and-validation .validation_alert [class^="icon"] {
width: auto;
margin: 0;
padding: 2px;
}
&:hover {
color: rgb(128, 169, 204);
}
.is--hidden {
height: 0;
width: 0;
padding: 0;
margin: 0;
pointer-events: none;
outline: none;
.xblock-inputs {
width: 100%;
overflow-y: scroll;
position: absolute;
bottom: 0;
top: 0;
}
.covered, .is--hidden {
display: none;
visibility: hidden;
.xblock-inputs.alerted {
top: 69px;
}
.error {
.xblock-inputs .error {
outline: none !important;
border:2px solid red !important;
box-shadow: 0 0 10px #719ECE !important;
}
#save-button.disabled {
background-color: gray;
cursor: auto;
}
#google-docs-actions{
.xblock-actions{
position: absolute;
bottom: 0;
}
.editor_content_wrapper {
width: 100%;
overflow-y: scroll;
position: absolute;
bottom: 0;
top: 0;
}
#xblock-inputs.alerted {
top: 69px;
.xblock-actions .save-button.disabled {
background-color: gray;
cursor: auto;
}
......@@ -17,7 +17,7 @@
max-width: 100%;
}
#validation_alert{
.user-inputs-and-validation .validation_alert{
width: 100%;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
......@@ -30,14 +30,19 @@
max-height: 200px;
}
.alert_icon{
.user-inputs-and-validation .validation_alert.covered {
display: none;
visibility: hidden;
}
.user-inputs-and-validation .validation_alert .alert_icon{
position: absolute;
top: 35%;
font-size: 200%;
left: 3%;
}
.alert_icon:before{
.user-inputs-and-validation .validation_alert .alert_icon:before{
font-family: "FontAwesome";
content: "\f071";
display: inline-block;
......@@ -47,69 +52,51 @@
width: 0;
}
.alert_header {
.user-inputs-and-validation .validation_alert .alert_header {
width: 85%;
margin: 0 5% 0 10%;
}
.alert_title {
.user-inputs-and-validation .validation_alert .alert_header .alert_title {
width: auto;
color: white;
}
.alert_message {
.user-inputs-and-validation .validation_alert .alert_header .alert_message {
font-size: 80%;
color: darkgray;
}
[class^="icon"] {
.user-inputs-and-validation .validation_alert [class^="icon"] {
width: auto;
margin: 0;
padding: 2px;
}
&:hover {
color: rgb(128, 169, 204);
}
.is--hidden {
height: 0;
width: 0;
padding: 0;
margin: 0;
pointer-events: none;
outline: none;
.xblock-inputs {
width: 100%;
overflow-y: scroll;
position: absolute;
bottom: 0;
top: 0;
}
.covered, .is--hidden {
display: none;
visibility: hidden;
.xblock-inputs.alerted {
top: 69px;
}
.error {
.xblock-inputs .error {
outline: none !important;
border:2px solid red;
box-shadow: 0 0 10px #719ECE;
}
#save-button.disabled {
background-color: gray;
cursor: auto;
border:2px solid red !important;
box-shadow: 0 0 10px #719ECE !important;
}
#google-docs-actions{
.xblock-actions{
position: absolute;
bottom: 0;
}
.editor_content_wrapper {
width: 100%;
overflow-y: scroll;
position: absolute;
bottom: 0;
top: 0;
}
#xblock-inputs.alerted {
top: 69px;
.xblock-actions .save-button.disabled {
background-color: gray;
cursor: auto;
}
function GoogleCalendarEditBlock(runtime, element, defaults) {
function GoogleCalendarEditBlock(runtime, element) {
var clear_name_button = $('.clear-display-name', element);
var clear_id_button = $('.clear-calendar-id', element);
var save_button = $('.save-button', element);
var validation_alert = $('#validation_alert', element);
var xblock_inputs_wrapper = $('#xblock-inputs', element);
var validation_alert = $('.validation_alert', element);
var xblock_inputs_wrapper = $('.xblock-inputs', element);
var edit_calendar_id_input = $('#edit_calendar_id', element);
var edit_display_name_input = $('#edit_display_name', element);
var error_message_div = $('.xblock-editor-error-message', element);
var defaultName = edit_display_name_input.attr('data-default-value');
var defaultID = edit_calendar_id_input.attr('data-default-value');
ToggleClearDefaultName();
ToggleClearCalendarID();
ToggleClear(edit_display_name_input, defaultName, clear_name_button);
ToggleClear(edit_calendar_id_input, defaultID, clear_id_button);
$('.clear-display-name', element).bind('click', function() {
$(this).addClass('inactive');
edit_display_name_input.val(defaults.defaultName);
edit_display_name_input.val(defaultName);
});
edit_display_name_input.bind('keyup', function(){
ToggleClearDefaultName();
ToggleClear(edit_display_name_input, defaultName, clear_name_button);
});
$('.clear-calendar-id', element).bind('click', function() {
$(this).addClass('inactive');
edit_calendar_id_input.val(defaults.defaultID);
edit_calendar_id_input.val(defaultID);
save_button.unbind('click').bind('click', SaveEditing);
if (!validation_alert.hasClass('covered')) {
......@@ -37,7 +38,7 @@ function GoogleCalendarEditBlock(runtime, element, defaults) {
});
edit_calendar_id_input.bind('keyup', function(){
ToggleClearCalendarID();
ToggleClear(edit_calendar_id_input, defaultID, clear_id_button);
var inputVal = $(this).val();
......@@ -61,25 +62,14 @@ function GoogleCalendarEditBlock(runtime, element, defaults) {
runtime.notify('cancel', {});
});
function ToggleClearDefaultName(){
if (edit_display_name_input.val() == defaults.defaultName){
if (!clear_name_button.hasClass('inactive')){
clear_name_button.addClass('inactive');
}
}
else {
clear_name_button.removeClass('inactive');
}
}
function ToggleClearCalendarID(){
if (edit_calendar_id_input.val() == defaults.defaultID){
if (!clear_id_button.hasClass('inactive')){
clear_id_button.addClass('inactive');
function ToggleClear(inputElement, defaultValue, clearButtonElement){
if (inputElement.val() == defaultValue){
if (!clearButtonElement.hasClass('inactive')){
clearButtonElement.addClass('inactive');
}
}
else {
clear_id_button.removeClass('inactive');
clearButtonElement.removeClass('inactive');
}
}
......
......@@ -14,23 +14,18 @@ function GoogleDocumentBlock(runtime, element) {
}
}
$('iframe', element).load(function(){
var iframe_url = $(this).attr('src');
$.ajax({
type: "POST",
url: runtime.handlerUrl(element, 'iframe_loaded'),
data: JSON.stringify({url: iframe_url})
});
});
$('iframe', element).load(SignalDocumentLoaded('iframe.loaded'));
$('img', element).load(function(){
var image_url = $(this).attr('src');
$('img', element).load(SignalDocumentLoaded('image.loaded'));
function SignalDocumentLoaded(event_name){
var document_url = $(this).attr('src');
$.ajax({
type: "POST",
url: runtime.handlerUrl(element, 'image_loaded'),
data: JSON.stringify({url: image_url})
url: runtime.handlerUrl(element, 'document_loaded'),
data: JSON.stringify({url: document_url, eventName: event_name})
});
});
}
});
}
......@@ -2,18 +2,19 @@ function GoogleDocumentEditBlock(runtime, element, defaults) {
var clear_name_button = $('.clear-display-name', element);
var save_button = $('.save-button', element);
var validation_alert = $('#validation_alert', element);
var validation_alert = $('.validation_alert', element);
var embed_code_textbox = $('#edit_embed_code', element);
var xblock_inputs_wrapper = $('#xblock-inputs', element);
var xblock_inputs_wrapper = $('.xblock-inputs', element);
var edit_display_name_input = $('#edit_display_name', element);
var error_message_div = $('.xblock-editor-error-message', element);
var defaultName = edit_display_name_input.attr('data-default-value');
ToggleClearDefaultName();
IsUrlValid();
$('.clear-display-name', element).bind('click', function() {
$(this).addClass('inactive');
edit_display_name_input.val(defaults.defaultName);
edit_display_name_input.val(defaultName);
});
edit_display_name_input.bind('keyup', function(){
......@@ -29,7 +30,7 @@ function GoogleDocumentEditBlock(runtime, element, defaults) {
});
function ToggleClearDefaultName(name, button){
if (edit_display_name_input.val() == defaults.defaultName){
if (edit_display_name_input.val() == defaultName){
if (!clear_name_button.hasClass('inactive')){
clear_name_button.addClass('inactive');
}
......
{% autoescape off %}
<div class="google-calendar-xblock-wrapper">
{{ iframe }}
{{ iframe|safe }}
</div>
{% endautoescape %}
......@@ -3,19 +3,19 @@
<!-- TODO: Replace by default edit view once available in Studio -->
<div class="wrapper-comp-settings is-active editor-with-buttons " id="settings-tab">
<div class="user-inputs-and-validation">
<div id="validation_alert" class="covered">
<div class="validation_alert covered">
<i class="alert_icon"></i>
<div class="alert_header">
<h2 class="alert_title">{% trans "Invalid Google Document" %}</h2>
<h2 class="alert_title">{% trans "Invalid Google Calendar" %}</h2>
<p class="alert_message">{% trans "Please correct the outlined fields." %}</p>
</div>
</div>
<div id="xblock-inputs" class="editor_content_wrapper">
<div class="xblock-inputs editor_content_wrapper">
<ul class="list-input settings-list">
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="edit_display_name">{% trans "Display Name" %}</label>
<input class="input setting-input edit-display-name" id="edit_display_name" value="{{ self.display_name }}" type="text">
<input class="input setting-input edit-display-name" id="edit_display_name" value="{{ self.display_name }}" type="text" data-default-value="{{defaultName}}">
<button class="action setting-clear clear-display-name" type="button" name="setting-clear">
<i class="icon-undo"></i>
<span class="sr">"<%= gettext("Clear Value") %>"</span>
......@@ -26,7 +26,7 @@
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="edit_calendar_id">{% trans "Public Calendar ID" %}</label>
<input class="input setting-input edit-calendar-id" id="edit_calendar_id" value="{{ self.calendar_id }}" type="text">
<input class="input setting-input edit-calendar-id" id="edit_calendar_id" value="{{ self.calendar_id }}" type="text" data-default-value="{{defaultID}}">
<button class="action setting-clear clear-calendar-id" type="button" name="setting-clear">
<i class="icon-undo"></i>
<span class="sr">"<%= gettext("Clear Value") %>"</span>
......@@ -53,15 +53,15 @@
</ul>
</div>
</div>
<div class="xblock-actions" id="google-calendar-actions">
<div class="xblock-actions">
<span class="xblock-editor-error-message"></span>
<ul>
<li class="action-item">
<a href="#" class="button action-primary save-button" id="save_button">{% trans "Save" %}</a>
<a href="#" class="button action-primary save-button">{% trans "Save" %}</a>
</li>
<li class="action-item">
<a href="#" class="button cancel-button" id="cancel_button">{% trans "Cancel" %}</a>
<a href="#" class="button cancel-button">{% trans "Cancel" %}</a>
</li>
</ul>
</div>
......
{% autoescape off %}
<div class="google-docs-xblock-wrapper">
{{ self.embed_code }}
{{ self.embed_code|safe }}
</div>
{% endautoescape %}
......@@ -3,19 +3,19 @@
<!-- TODO: Replace by default edit view once available in Studio -->
<div class="wrapper-comp-settings is-active editor-with-buttons " id="settings-tab">
<div class="user-inputs-and-validation">
<div id="validation_alert" class="covered">
<div class="validation_alert covered">
<i class="alert_icon"></i>
<div class="alert_header">
<h2 class="alert_title">{% trans "Invalid Google Document" %}</h2>
<p class="alert_message">{% trans "Please correct the outlined fields." %}</p>
</div>
</div>
<div id="xblock-inputs" class="editor_content_wrapper">
<div class="xblock-inputs editor_content_wrapper">
<ul class="list-input settings-list">
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="edit_display_name">{% trans "Display Name" %}</label>
<input class="input setting-input edit-display-name" id="edit_display_name" value="{{ self.display_name }}" type="text">
<input class="input setting-input edit-display-name" id="edit_display_name" value="{{ self.display_name }}" type="text" data-default-value="{{defaultName}}">
<button class="action setting-clear clear-display-name" type="button" name="setting-clear">
<i class="icon-undo"></i>
<span class="sr">"<%= gettext("Clear Value") %>"</span>
......@@ -37,7 +37,7 @@
<span class="xblock-editor-error-message"></span>
<ul>
<li class="action-item">
<a href="#" class="button action-primary save-button" id="save_button">{% trans "Save" %}</a>
<a href="#" class="button action-primary save-button">{% trans "Save" %}</a>
</li>
<li class="action-item">
......
......@@ -8,6 +8,8 @@ import pkg_resources
from django.template import Context, Template
from xblockutils.resources import ResourceLoader
# Globals ###########################################################
......@@ -16,20 +18,7 @@ log = logging.getLogger(__name__)
# Functions #########################################################
def load_resource(resource_path):
"""
Gets the content of a resource
"""
resource_content = pkg_resources.resource_string(__name__, resource_path)
return resource_content.decode("utf-8")
def render_template(template_path, context={}):
"""
Evaluate a template by resource path, applying the provided context
"""
template_str = load_resource(template_path)
template = Template(template_str)
return template.render(Context(context))
loader = ResourceLoader(__name__)
class AttrDict(dict):
def __init__(self, *args, **kwargs):
......
-e .
-e git://github.com/nosedjango/nosedjango.git@ed7d7f9aa969252ff799ec159f828eaa8c1cbc5a#egg=nosedjango-dev
lxml==3.0.1
-e git://github.com/edx-solutions/xblock-utils.git#egg=xblock-utils
......@@ -29,7 +29,9 @@ setup(
],
install_requires=[
'XBlock',
'xblock-utils',
],
dependency_links = ['http://github.com/edx-solutions/xblock-utils/tarball/master#egg=xblock-utils'],
entry_points={
'xblock.v1': [
'google-document = google_drive:GoogleDocumentBlock',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment