Skip to content

Commit

Permalink
Change the schema for dict fields to specify the properties as a list…
Browse files Browse the repository at this point in the history
…, so that the corresponding fields can be ordered appropriately in the editor view.
  • Loading branch information
seanlip committed Aug 18, 2014
1 parent 80a743c commit 79876fc
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 119 deletions.
6 changes: 3 additions & 3 deletions core/templates/dev/head/components/formBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ oppia.directive('unicodeWithParametersEditor', ['$modal', '$log', 'warningsData'
// TODO(sll): This is a somewhat hacky solution. Can it be cleaned up?
$timeout(function() {
$scope.currentlyEditing = false;
}, 5000);
}, 50);
});
});

Expand Down Expand Up @@ -451,8 +451,8 @@ oppia.factory('schemaDefaultValueService', [function() {
return [];
} else if (schema.type === 'dict') {
var result = {};
for (var key in schema.properties) {
result[key] = this.getDefaultValue(schema.properties[key]);
for (var i = 0; i < schema.properties.length; i++) {
result[schema.properties[i].name] = this.getDefaultValue(schema.properties[i].schema);
}
return result;
} else if (schema.type === 'int' || schema.type === 'float') {
Expand Down
40 changes: 24 additions & 16 deletions core/templates/dev/head/components/formBuilderTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,29 +122,34 @@ oppia.controller('FormBuilderTests', [
name: 'Dict with a bool, a unicode string and a list of ints. The string must be either \'abc\' or \'def\'.',
schema: {
type: 'dict',
properties: {
a_boolean: {
type: 'bool'
},
a_unicode_string: {
properties: [{
name: 'a_unicode_string_appearing_first',
schema: {
type: 'unicode',
post_normalizers: [{
id: 'require_is_one_of',
choices: ['abc', 'def']
}]
},
a_list: {
}
}, {
name: 'a_list_appearing_second',
schema: {
type: 'list',
items: {
type: 'int'
}
}
}
}, {
name: 'a_boolean_appearing_last',
schema: {
type: 'bool'
}
}]
},
value: {
a_boolean: false,
a_unicode_string: 'abc',
a_list: [2, 3]
a_boolean_appearing_last: false,
a_unicode_string_appearing_first: 'abc',
a_list_appearing_second: [2, 3]
}
}, {
name: 'List of unicode strings',
Expand All @@ -171,14 +176,17 @@ oppia.controller('FormBuilderTests', [
type: 'list',
items: {
type: 'dict',
properties: {
intField: {
properties: [{
name: 'intField',
schema: {
type: 'int',
},
htmlField: {
}
}, {
name: 'htmlField',
schema: {
type: 'html'
}
}
}]
}
},
value: [{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@

<script type="text/ng-template" id="schemaBasedEditor/dict">
<form role="form">
<div ng-repeat="(key, schema) in propertySchemas()">
<div ng-repeat="property in propertySchemas()">
<div class="form-group">
<!-- TODO(sll): Add a 'for' attribute to the label tag. -->
<label><[key]></label>
<schema-builder schema="schema" mode="mode" local-value="localValue[key]">
<label><[property.name]></label>
<schema-builder schema="property.schema" mode="mode" local-value="localValue[property.name]">
</schema-builder>
</div>
</div>
Expand Down
20 changes: 18 additions & 2 deletions core/templates/dev/head/components/richTextEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,29 @@ oppia.directive('richTextEditor', [
});
};

$scope.currentlyEditing = false;
$scope.$watch('htmlContent', function(newValue, oldValue) {
if ($scope.hasFullyLoaded && !$scope.currentlyEditing) {
// This is an external change.
console.log($scope.htmlContent);
$scope.rteContent = $scope._convertHtmlToRte(newValue);
$(rteNode).wysiwyg('setContent', $scope.rteContent);
}
});

$scope._saveContent = function() {
var content = $(rteNode).wysiwyg('getContent');
if (content !== null && content !== undefined) {
$scope.htmlContent = $scope._convertRteToHtml(content);
// The following $timeout removes the '$apply in progress' errors.
$timeout(function() {
$scope.$apply();
$scope.$apply(function() {
$scope.currentlyEditing = true;
$scope.htmlContent = $scope._convertRteToHtml(content);
// TODO(sll): This is a somewhat hacky solution. Can it be cleaned up?
$timeout(function() {
$scope.currentlyEditing = false;
}, 50);
});
});
}
};
Expand Down
108 changes: 37 additions & 71 deletions extensions/objects/models/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,19 @@ class CodeEvaluation(BaseObject):

SCHEMA = {
'type': 'dict',
'properties': {
'code': UnicodeString.SCHEMA,
'output': UnicodeString.SCHEMA,
'evaluation': UnicodeString.SCHEMA,
'error': UnicodeString.SCHEMA,
}
'properties': [{
'name': 'code',
'schema': UnicodeString.SCHEMA,
}, {
'name': 'output',
'schema': UnicodeString.SCHEMA,
}, {
'name': 'evaluation',
'schema': UnicodeString.SCHEMA,
}, {
'name': 'error',
'schema': UnicodeString.SCHEMA,
}]
}


Expand Down Expand Up @@ -263,48 +270,6 @@ class MathLatexString(BaseObject):
SCHEMA = UnicodeString.SCHEMA


class TabContent(BaseObject):
"""Class for editing the content of a single tab.
The object is described by a dict with two keys: 'title' and 'content'.
These have types UnicodeString and Html respectively.
"""

description = 'Content for a single tab.'
edit_html_filename = 'tab_content_editor'
edit_js_filename = 'TabContentEditor'

SCHEMA = {
'type': 'dict',
'properties': {
'title': {
'type': 'unicode',
'post_normalizers': [{
'id': 'require_nonempty'
}]
},
'content': Html.SCHEMA,
}
}


class ListOfTabContent(BaseObject):
"""Class for editing the content of a tabbed view.
The object is described by a list of dicts, each representing a TabContent
object.
"""

description = 'Content for a set of tabs.'
edit_html_filename = 'list_editor'
edit_js_filename = 'ListOfTabContentEditor'

SCHEMA = {
'type': 'list',
'items': TabContent.SCHEMA,
}


class SanitizedUrl(BaseObject):
"""HTTP or HTTPS url string class."""

Expand All @@ -328,12 +293,21 @@ class MusicPhrase(BaseObject):
edit_html_filename = 'music_phrase_editor'
edit_js_filename = 'MusicPhraseEditor'

_FRACTION_PART_SCHEMA = {
'type': 'int',
'post_normalizers': [{
'id': 'require_at_least',
'min_value': 1
}]
}

SCHEMA = {
'type': 'list',
'items': {
'type': 'dict',
'properties': {
'readableNoteName': {
'properties': [{
'name': 'readableNoteName',
'schema': {
'type': 'unicode',
'post_normalizers': [{
'id': 'require_is_one_of',
Expand All @@ -342,28 +316,20 @@ class MusicPhrase(BaseObject):
'D5', 'E5', 'F5', 'G5', 'A5'
]
}]
},
'noteDuration': {
}
}, {
'name': 'noteDuration',
'schema': {
'type': 'dict',
'properties': {
'num': {
'type': 'int',
'post_normalizers': [{
'id': 'require_at_least',
'min_value': 1
}]
},
'den': {
'type': 'int',
'post_normalizers': [{
'id': 'require_at_least',
'min_value': 1
}]
}
}
},
}

'properties': [{
'name': 'num',
'schema': _FRACTION_PART_SCHEMA
}, {
'name': 'den',
'schema': _FRACTION_PART_SCHEMA
}]
}
}],
}
}

Expand Down
13 changes: 8 additions & 5 deletions extensions/widgets/noninteractive/Tabs/Tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@

TAB_CONTENT_SCHEMA = {
'type': 'dict',
'properties': {
'title': {
'properties': [{
'name': 'title',
'schema': {
'type': 'unicode',
'post_normalizers': [{
'id': 'require_nonempty'
}]
},
'content': {
}
}, {
'name': 'content',
'schema': {
'type': 'html',
}
}
}]
}


Expand Down
17 changes: 11 additions & 6 deletions schema_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
SCHEMA_KEY_TYPE = 'type'
SCHEMA_KEY_POST_NORMALIZERS = 'post_normalizers'
SCHEMA_KEY_CHOICES = 'choices'
SCHEMA_KEY_NAME = 'name'
SCHEMA_KEY_SCHEMA = 'schema'

SCHEMA_TYPE_BOOL = 'bool'
SCHEMA_TYPE_DICT = 'dict'
Expand Down Expand Up @@ -69,12 +71,15 @@ def normalize_against_schema(obj, schema):
normalized_obj = obj
elif schema[SCHEMA_KEY_TYPE] == SCHEMA_TYPE_DICT:
assert isinstance(obj, dict), ('Expected dict, received %s' % obj)
assert set(obj.keys()) == set(schema[SCHEMA_KEY_PROPERTIES].keys())
normalized_obj = {
key: normalize_against_schema(
obj[key], schema[SCHEMA_KEY_PROPERTIES][key])
for key in schema[SCHEMA_KEY_PROPERTIES]
}
expected_dict_keys = [
p[SCHEMA_KEY_NAME] for p in schema[SCHEMA_KEY_PROPERTIES]]
assert set(obj.keys()) == set(expected_dict_keys)

normalized_obj = {}
for prop in schema[SCHEMA_KEY_PROPERTIES]:
key = prop[SCHEMA_KEY_NAME]
normalized_obj[key] = normalize_against_schema(
obj[key], prop[SCHEMA_KEY_SCHEMA])
elif schema[SCHEMA_KEY_TYPE] == SCHEMA_TYPE_FLOAT:
obj = float(obj)
assert isinstance(obj, numbers.Real), (
Expand Down
Loading

0 comments on commit 79876fc

Please sign in to comment.