diff --git a/core/domain/rte_component_registry_test.py b/core/domain/rte_component_registry_test.py index 85b96508e4eb..88b51bfbaef8 100644 --- a/core/domain/rte_component_registry_test.py +++ b/core/domain/rte_component_registry_test.py @@ -152,7 +152,8 @@ def test_rte_components_are_valid(self): self.assertTrue(os.path.isfile(protractor_file)) main_js_file = os.path.join( - directives_dir, '%sDirective.js' % component_id) + directives_dir, 'OppiaNoninteractive%sDirective.js' + % component_id) main_html_file = os.path.join( directives_dir, '%s_directive.html' % component_id.lower()) diff --git a/core/domain/value_generators_domain.py b/core/domain/value_generators_domain.py index 133b9cb8a71d..028c7e47f256 100644 --- a/core/domain/value_generators_domain.py +++ b/core/domain/value_generators_domain.py @@ -72,7 +72,7 @@ def get_js_template(cls): # customizationArgs and objType. return utils.get_file_contents(os.path.join( os.getcwd(), feconf.VALUE_GENERATORS_DIR, 'templates', - '%s.js' % cls.__name__)) + '%sDirective.js' % cls.__name__)) def generate_value(self, *args, **kwargs): """Generates a new value, using the given customization args. diff --git a/core/domain/visualization_registry.py b/core/domain/visualization_registry.py index 2736684f922b..769c1b51345c 100644 --- a/core/domain/visualization_registry.py +++ b/core/domain/visualization_registry.py @@ -51,8 +51,14 @@ def _refresh_registry(cls): @classmethod def get_full_html(cls): """Returns the HTML bodies for all visualizations.""" - js_directives = utils.get_file_contents(os.path.join( - feconf.VISUALIZATIONS_DIR, 'visualizations.js')) + js_directives = '' + for visualization_class in cls.get_all_visualization_ids(): + filename = ( + 'OppiaVisualization%sDirective.js' % (visualization_class)) + js_directives += ( + utils.get_file_contents(os.path.join( + feconf.VISUALIZATIONS_DIR, filename))) + return '\n' % (js_directives) @classmethod diff --git a/core/templates/dev/head/app.js b/core/templates/dev/head/App.js similarity index 100% rename from core/templates/dev/head/app.js rename to core/templates/dev/head/App.js diff --git a/core/templates/dev/head/i18n.js b/core/templates/dev/head/I18nFooter.js similarity index 100% rename from core/templates/dev/head/i18n.js rename to core/templates/dev/head/I18nFooter.js diff --git a/core/templates/dev/head/components/forms/ApplyValidationDirective.js b/core/templates/dev/head/components/forms/ApplyValidationDirective.js new file mode 100644 index 000000000000..2d1653539ee2 --- /dev/null +++ b/core/templates/dev/head/components/forms/ApplyValidationDirective.js @@ -0,0 +1,61 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for applying validation. + */ + +/* eslint-disable angular/directive-restrict */ +oppia.directive('applyValidation', ['$filter', function($filter) { + return { + require: 'ngModel', + restrict: 'A', + link: function(scope, elm, attrs, ctrl) { + // Add validators in reverse order. + if (scope.validators()) { + scope.validators().forEach(function(validatorSpec) { + var frontendName = $filter('underscoresToCamelCase')( + validatorSpec.id); + + // Note that there may not be a corresponding frontend filter for + // each backend validator. + try { + $filter(frontendName); + } catch (err) { + return; + } + + var filterArgs = {}; + for (var key in validatorSpec) { + if (key !== 'id') { + filterArgs[$filter('underscoresToCamelCase')(key)] = + angular.copy(validatorSpec[key]); + } + } + + var customValidator = function(viewValue) { + ctrl.$setValidity( + frontendName, $filter(frontendName)(viewValue, + filterArgs)); + return viewValue; + }; + + ctrl.$parsers.unshift(customValidator); + ctrl.$formatters.unshift(customValidator); + }); + } + } + }; +}]); +/* eslint-enable angular/directive-restrict */ diff --git a/core/templates/dev/head/components/forms/ConvertHtmlToUnicodeFilter.js b/core/templates/dev/head/components/forms/ConvertHtmlToUnicodeFilter.js new file mode 100644 index 000000000000..0741d0826d01 --- /dev/null +++ b/core/templates/dev/head/components/forms/ConvertHtmlToUnicodeFilter.js @@ -0,0 +1,23 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Converts HTML to unicode. + */ + +oppia.filter('convertHtmlToUnicode', [function() { + return function(html) { + return angular.element('
' + html + '
').text(); + }; +}]); diff --git a/core/templates/dev/head/components/forms/ConvertUnicodeToHtmlFilter.js b/core/templates/dev/head/components/forms/ConvertUnicodeToHtmlFilter.js new file mode 100644 index 000000000000..686bd246de5b --- /dev/null +++ b/core/templates/dev/head/components/forms/ConvertUnicodeToHtmlFilter.js @@ -0,0 +1,26 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Converts unicode to HTML. + */ + +oppia.filter('convertUnicodeToHtml', [ + '$sanitize', 'HtmlEscaperService', + function($sanitize, HtmlEscaperService) { + return function(text) { + return $sanitize(HtmlEscaperService.unescapedStrToEscapedStr(text)); + }; + } +]); diff --git a/core/templates/dev/head/components/forms/ConvertUnicodeWithParamsToHtmlFilter.js b/core/templates/dev/head/components/forms/ConvertUnicodeWithParamsToHtmlFilter.js new file mode 100644 index 000000000000..7b082c3a8e90 --- /dev/null +++ b/core/templates/dev/head/components/forms/ConvertUnicodeWithParamsToHtmlFilter.js @@ -0,0 +1,95 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Converts {{name}} substrings to + * name tags and unescapes the + * {, } and \ characters. This is done by reading the given string from + * left to right: if we see a backslash, we use the following character; + * if we see a '{{', this is the start of a parameter; if we see a '}}'; + * this is the end of a parameter. + */ + +oppia.filter('convertUnicodeWithParamsToHtml', ['$filter', function($filter) { + var assert = function(text) { + if (!text) { + throw 'Invalid unicode-string-with-parameters: ' + text; + } + }; + + return function(text) { + // The parsing here needs to be done with more care because we are replacing + // two-character strings. We can't naively break by {{ because in strings + // like \{{{ the second and third characters will be taken as the opening + // brackets, which is wrong. We can't unescape characters because then the + // { characters that remain will be ambiguous (they may either be the + // openings of parameters or literal '{' characters entered by the user. + // So we build a standard left-to-right parser which examines each + // character of the string in turn, and processes it accordingly. + var textFragments = []; + var currentFragment = ''; + var currentFragmentIsParam = false; + for (var i = 0; i < text.length; i++) { + if (text[i] === '\\') { + assert(!currentFragmentIsParam && text.length > i + 1 && { + '{': true, + '}': true, + '\\': true + }[text[i + 1]]); + currentFragment += text[i + 1]; + i++; + } else if (text[i] === '{') { + assert( + text.length > i + 1 && !currentFragmentIsParam && + text[i + 1] === '{'); + textFragments.push({ + type: 'text', + data: currentFragment + }); + currentFragment = ''; + currentFragmentIsParam = true; + i++; + } else if (text[i] === '}') { + assert( + text.length > i + 1 && currentFragmentIsParam && + text[i + 1] === '}'); + textFragments.push({ + type: 'parameter', + data: currentFragment + }); + currentFragment = ''; + currentFragmentIsParam = false; + i++; + } else { + currentFragment += text[i]; + } + } + + assert(!currentFragmentIsParam); + textFragments.push({ + type: 'text', + data: currentFragment + }); + + var result = ''; + textFragments.forEach(function(fragment) { + result += ( + fragment.type === 'text' ? + $filter('convertUnicodeToHtml')(fragment.data) : + '' + fragment.data + + ''); + }); + return result; + }; +}]); diff --git a/core/templates/dev/head/components/forms/FormBuilder.js b/core/templates/dev/head/components/forms/FormBuilder.js deleted file mode 100644 index 0bfd1e4693ee..000000000000 --- a/core/templates/dev/head/components/forms/FormBuilder.js +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2014 The Oppia Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Directives for schema-based form builders. - */ - -// NOTE TO DEVELOPERS: This forms framework accepts an external event -// named 'schemaBasedFormsShown'. This should be called by clients -// when these forms first come into view. - -oppia.filter('convertHtmlToUnicode', [function() { - return function(html) { - return angular.element('
' + html + '
').text(); - }; -}]); - -oppia.filter('convertUnicodeToHtml', [ - '$sanitize', 'HtmlEscaperService', - function($sanitize, HtmlEscaperService) { - return function(text) { - return $sanitize(HtmlEscaperService.unescapedStrToEscapedStr(text)); - }; - } -]); - -// Converts {{name}} substrings to name tags -// and unescapes the {, } and \ characters. This is done by reading the given -// string from left to right: if we see a backslash, we use the following -// character; if we see a '{{', this is the start of a parameter; if -// we see a '}}'; this is the end of a parameter. -oppia.filter('convertUnicodeWithParamsToHtml', ['$filter', function($filter) { - var assert = function(text) { - if (!text) { - throw 'Invalid unicode-string-with-parameters: ' + text; - } - }; - - return function(text) { - // The parsing here needs to be done with more care because we are replacing - // two-character strings. We can't naively break by {{ because in strings - // like \{{{ the second and third characters will be taken as the opening - // brackets, which is wrong. We can't unescape characters because then the - // { characters that remain will be ambiguous (they may either be the - // openings of parameters or literal '{' characters entered by the user. - // So we build a standard left-to-right parser which examines each - // character of the string in turn, and processes it accordingly. - var textFragments = []; - var currentFragment = ''; - var currentFragmentIsParam = false; - for (var i = 0; i < text.length; i++) { - if (text[i] === '\\') { - assert(!currentFragmentIsParam && text.length > i + 1 && { - '{': true, - '}': true, - '\\': true - }[text[i + 1]]); - currentFragment += text[i + 1]; - i++; - } else if (text[i] === '{') { - assert( - text.length > i + 1 && !currentFragmentIsParam && - text[i + 1] === '{'); - textFragments.push({ - type: 'text', - data: currentFragment - }); - currentFragment = ''; - currentFragmentIsParam = true; - i++; - } else if (text[i] === '}') { - assert( - text.length > i + 1 && currentFragmentIsParam && - text[i + 1] === '}'); - textFragments.push({ - type: 'parameter', - data: currentFragment - }); - currentFragment = ''; - currentFragmentIsParam = false; - i++; - } else { - currentFragment += text[i]; - } - } - - assert(!currentFragmentIsParam); - textFragments.push({ - type: 'text', - data: currentFragment - }); - - var result = ''; - textFragments.forEach(function(fragment) { - result += ( - fragment.type === 'text' ? - $filter('convertUnicodeToHtml')(fragment.data) : - '' + fragment.data + - ''); - }); - return result; - }; -}]); - -// The names of these filters must correspond to the names of the backend -// validators (with underscores converted to camelcase). -// WARNING: These filters do not validate the arguments supplied with the -// validator definitions in the schema; these are assumed to be correct. -oppia.filter('isAtLeast', [function() { - return function(input, args) { - return (input >= args.minValue); - }; -}]); - -oppia.filter('isAtMost', [function() { - return function(input, args) { - return (input <= args.maxValue); - }; -}]); - -oppia.filter('isNonempty', [function() { - return function(input) { - return Boolean(input); - }; -}]); - -oppia.filter('isInteger', [function() { - return function(input) { - return Number.isInteger(Number(input)); - }; -}]); - -oppia.filter('isFloat', [function() { - return function(input) { - var FLOAT_REGEXP = /(?=.*\d)^\-?\d*(\.|\,)?\d*\%?$/; - // This regex accepts floats in the following formats: - // 0. - // 0.55.. - // -0.55.. - // .555.. - // -.555.. - // All examples above with '.' replaced with ',' are also valid. - // Expressions containing % are also valid (5.1% etc). - - var viewValue = ''; - try { - viewValue = input.toString().trim(); - } catch (e) { - return undefined; - } - - if (viewValue !== '' && FLOAT_REGEXP.test(viewValue)) { - if (viewValue.slice(-1) === '%') { - // This is a percentage, so the input needs to be divided by 100. - return parseFloat( - viewValue.substring(0, viewValue.length - 1).replace(',', '.') - ) / 100.0; - } else { - return parseFloat(viewValue.replace(',', '.')); - } - } else { - return undefined; - } - }; -}]); - -/* eslint-disable angular/directive-restrict */ -oppia.directive('applyValidation', ['$filter', function($filter) { - return { - require: 'ngModel', - restrict: 'A', - link: function(scope, elm, attrs, ctrl) { - // Add validators in reverse order. - if (scope.validators()) { - scope.validators().forEach(function(validatorSpec) { - var frontendName = $filter('underscoresToCamelCase')( - validatorSpec.id); - - // Note that there may not be a corresponding frontend filter for - // each backend validator. - try { - $filter(frontendName); - } catch (err) { - return; - } - - var filterArgs = {}; - for (var key in validatorSpec) { - if (key !== 'id') { - filterArgs[$filter('underscoresToCamelCase')(key)] = - angular.copy(validatorSpec[key]); - } - } - - var customValidator = function(viewValue) { - ctrl.$setValidity( - frontendName, $filter(frontendName)(viewValue, - filterArgs)); - return viewValue; - }; - - ctrl.$parsers.unshift(customValidator); - ctrl.$formatters.unshift(customValidator); - }); - } - } - }; -}]); -/* eslint-enable angular/directive-restrict */ - -// This should come before 'apply-validation', if that is defined as -// an attribute on the HTML tag. - -/* eslint-disable angular/directive-restrict */ -oppia.directive('requireIsFloat', ['$filter', function($filter) { - return { - require: 'ngModel', - restrict: 'A', - link: function(scope, elm, attrs, ctrl) { - var floatValidator = function(viewValue) { - var filteredValue = $filter('isFloat')(viewValue); - ctrl.$setValidity('isFloat', filteredValue !== undefined); - return filteredValue; - }; - - ctrl.$parsers.unshift(floatValidator); - ctrl.$formatters.unshift(floatValidator); - } - }; -}]); -/* eslint-enable angular/directive-restrict */ diff --git a/core/templates/dev/head/components/forms/HtmlSelectDirective.js b/core/templates/dev/head/components/forms/HtmlSelectDirective.js index bea11ef77975..6def305f5b31 100644 --- a/core/templates/dev/head/components/forms/HtmlSelectDirective.js +++ b/core/templates/dev/head/components/forms/HtmlSelectDirective.js @@ -13,7 +13,7 @@ // limitations under the License. /** - * @fileoverview Directive for the select supporting html + * @fileoverview Directive for the selection dropdown with HTML content. */ // This directive allows user to put html into select's options. diff --git a/core/templates/dev/head/components/forms/RequireIsFloatDirective.js b/core/templates/dev/head/components/forms/RequireIsFloatDirective.js new file mode 100644 index 000000000000..729981175a96 --- /dev/null +++ b/core/templates/dev/head/components/forms/RequireIsFloatDirective.js @@ -0,0 +1,39 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for requiring "isFloat" filter. + */ + +// This should come before 'apply-validation', if that is defined as +// an attribute on the HTML tag. + +/* eslint-disable angular/directive-restrict */ +oppia.directive('requireIsFloat', ['$filter', function($filter) { + return { + require: 'ngModel', + restrict: 'A', + link: function(scope, elm, attrs, ctrl) { + var floatValidator = function(viewValue) { + var filteredValue = $filter('isFloat')(viewValue); + ctrl.$setValidity('isFloat', filteredValue !== undefined); + return filteredValue; + }; + + ctrl.$parsers.unshift(floatValidator); + ctrl.$formatters.unshift(floatValidator); + } + }; +}]); +/* eslint-enable angular/directive-restrict */ diff --git a/core/templates/dev/head/components/forms/validators/IsAtLeastFilter.js b/core/templates/dev/head/components/forms/validators/IsAtLeastFilter.js new file mode 100644 index 000000000000..789c1ed10046 --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/IsAtLeastFilter.js @@ -0,0 +1,24 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Validator to check if input is greater than + args. + */ + +oppia.filter('isAtLeast', [function() { + return function(input, args) { + return (input >= args.minValue); + }; +}]); diff --git a/core/templates/dev/head/components/forms/validators/IsAtMostFilter.js b/core/templates/dev/head/components/forms/validators/IsAtMostFilter.js new file mode 100644 index 000000000000..79be9f3a79b2 --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/IsAtMostFilter.js @@ -0,0 +1,24 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Validator to check if input is less than + args. + */ + +oppia.filter('isAtMost', [function() { + return function(input, args) { + return (input <= args.maxValue); + }; +}]); diff --git a/core/templates/dev/head/components/forms/validators/IsFloatFilter.js b/core/templates/dev/head/components/forms/validators/IsFloatFilter.js new file mode 100644 index 000000000000..3ef52f590b34 --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/IsFloatFilter.js @@ -0,0 +1,51 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Validator to check if input is float. + */ + +oppia.filter('isFloat', [function() { + return function(input) { + var FLOAT_REGEXP = /(?=.*\d)^\-?\d*(\.|\,)?\d*\%?$/; + // This regex accepts floats in the following formats: + // 0. + // 0.55.. + // -0.55.. + // .555.. + // -.555.. + // All examples above with '.' replaced with ',' are also valid. + // Expressions containing % are also valid (5.1% etc). + + var viewValue = ''; + try { + viewValue = input.toString().trim(); + } catch (e) { + return undefined; + } + + if (viewValue !== '' && FLOAT_REGEXP.test(viewValue)) { + if (viewValue.slice(-1) === '%') { + // This is a percentage, so the input needs to be divided by 100. + return parseFloat( + viewValue.substring(0, viewValue.length - 1).replace(',', '.') + ) / 100.0; + } else { + return parseFloat(viewValue.replace(',', '.')); + } + } else { + return undefined; + } + }; +}]); diff --git a/core/templates/dev/head/components/forms/validators/IsIntegerFilter.js b/core/templates/dev/head/components/forms/validators/IsIntegerFilter.js new file mode 100644 index 000000000000..1c6968e5bb5a --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/IsIntegerFilter.js @@ -0,0 +1,23 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Validator to check if input is integer. + */ + +oppia.filter('isInteger', [function() { + return function(input) { + return Number.isInteger(Number(input)); + }; +}]); diff --git a/core/templates/dev/head/components/forms/validators/IsNonemptyFilter.js b/core/templates/dev/head/components/forms/validators/IsNonemptyFilter.js new file mode 100644 index 000000000000..473bc1a54095 --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/IsNonemptyFilter.js @@ -0,0 +1,23 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Validator to check if input is nonempty. + */ + +oppia.filter('isNonempty', [function() { + return function(input) { + return Boolean(input); + }; +}]); diff --git a/core/templates/dev/head/components/forms/validators/README.md b/core/templates/dev/head/components/forms/validators/README.md new file mode 100644 index 000000000000..e341eb90cd76 --- /dev/null +++ b/core/templates/dev/head/components/forms/validators/README.md @@ -0,0 +1,4 @@ +The names of these filters must correspond to the names of the backend +validators (with underscores converted to camelcase). +WARNING: These filters do not validate the arguments supplied with the +validator definitions in the schema; these are assumed to be correct. diff --git a/core/templates/dev/head/components/rich_text_components.html b/core/templates/dev/head/components/rich_text_components.html index 1ecbd147945e..9c494db2d07c 100644 --- a/core/templates/dev/head/components/rich_text_components.html +++ b/core/templates/dev/head/components/rich_text_components.html @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/core/templates/dev/head/components/version_diff_visualization_directive.html b/core/templates/dev/head/components/version_diff_visualization_directive.html index 3d3e0edb075e..e52b5a98e237 100644 --- a/core/templates/dev/head/components/version_diff_visualization_directive.html +++ b/core/templates/dev/head/components/version_diff_visualization_directive.html @@ -5,7 +5,7 @@
-

Exploration Graph Legend

-
0) { - if ((unitList.length > 0) && isunit(unitList.slice(-1).pop())) { - unitList.push('*'); - } - unitList.push(unit); - unit = ''; - } - if (!('# '.includes(units[i]))) { - unitList.push(units[i]); - } - } else if (units[i] === ' ' && unit === 'per') { - unitList.push('/'); - unit = ''; - } else { - unit += units[i]; - } - } - return unitList; - }; - - var unitWithMultiplier = function(unitList) { - var multiplier = 1; - var unitsWithMultiplier = []; - var parenthesisStack = []; - - for (var ind = 0; ind < unitList.length; ind++) { - if (unitList[ind] === '/') { - multiplier = -multiplier; - } else if (unitList[ind] === '(') { - if (unitList[ind - 1] === '/') { - // If previous element was division then we need to inverse - // multiplier when we find its corresponsing closing parenthesis. - // Second element of pushed element is used for this purpose. - parenthesisStack.push(['(', -1]); - } else { - // If previous element was not division then we don't need to - // invert the multiplier. - parenthesisStack.push(['(', 1]); - } - } else if (unitList[ind] === ')') { - var elem = parenthesisStack.pop(); - multiplier = parseInt(elem[1]) * multiplier; - } else if (isunit(unitList[ind])) { - unitsWithMultiplier.push([unitList[ind], multiplier]); - // If previous element was division then we need to invert - // multiplier. - if (unitList[ind - 1] === '/') { - multiplier = -multiplier; - } - } - } - return unitsWithMultiplier; - }; - - var convertUnitDictToList = function(unitDict) { - var unitList = []; - for (var key in unitDict) { - unitList.push({unit: key, exponent: unitDict[key]}); - } - return unitList; - }; - - var unitToList = function(unitsWithMultiplier) { - var unitDict = {}; - for (var i = 0; i < unitsWithMultiplier.length; i++) { - var unit = unitsWithMultiplier[i][0]; - var multiplier = unitsWithMultiplier[i][1]; - var ind = unit.indexOf('^'); - if (ind > -1) { - var s = unit.substr(0, ind); - var power = parseInt(unit.substr(ind + 1)); - } else { - var s = unit; - var power = 1; - } - if (!(s in unitDict)) { - unitDict[s] = 0; - } - unitDict[s] += multiplier * power; - } - return convertUnitDictToList(unitDict); - }; - - Units.prototype.toDict = function() { - return { - units: this.units - }; - }; - - Units.fromList = function(unitsList) { - return new Units(unitsList); - }; - - Units.fromStringToList = function(unitsString) { - return unitToList(unitWithMultiplier(Units.stringToLexical(unitsString))); - }; - - Units.prototype.toString = function() { - var unit = ''; - for (var i = 0; i < this.units.length; i++) { - var d = this.units[i]; - if (d.exponent === 1) { - unit += d.unit + ' '; - } else { - unit += d.unit + '^' + d.exponent.toString() + ' '; - } - } - return unit.trim(); - }; - - Units.createCurrencyUnits = function() { - // Creates user-defined currency (base + sub) units. - var keys = Object.keys(CURRENCY_UNITS); - for (var i = 0; i < keys.length; i++) { - if (CURRENCY_UNITS[keys[i]].base_unit === null) { - // Base unit (like: rupees, dollar etc.). - math.createUnit(CURRENCY_UNITS[keys[i]].name, { - aliases: CURRENCY_UNITS[keys[i]].aliases}); - } else { - // Sub unit (like: paise, cents etc.). - math.createUnit(CURRENCY_UNITS[keys[i]].name, { - definition: CURRENCY_UNITS[keys[i]].base_unit, - aliases: CURRENCY_UNITS[keys[i]].aliases}); - } - } - }; - - Units.toMathjsCompatibleString = function(units) { - // Makes the units compatible with the math.js allowed format. - units = units.replace(/per/g, '/'); - - // Special symbols need to be replaced as math.js doesn't support custom - // units starting with special symbols. Also, it doesn't allow units - // followed by a number as in the case of currency units. - var keys = Object.keys(CURRENCY_UNITS); - for (var i = 0; i < keys.length; i++) { - for (var j = 0; j < CURRENCY_UNITS[keys[i]].front_units.length; j++) { - if (units.includes(CURRENCY_UNITS[keys[i]].front_units[j])) { - units = units.replace(CURRENCY_UNITS[keys[i]].front_units[j], ''); - units = CURRENCY_UNITS[keys[i]].name + units; - } - } - - for (var j = 0; j < CURRENCY_UNITS[keys[i]].aliases.length; j++) { - if (units.includes(CURRENCY_UNITS[keys[i]].aliases[j])) { - units = units.replace(CURRENCY_UNITS[keys[i]].aliases[j], - CURRENCY_UNITS[keys[i]].name); - } - } - } - return units.trim(); - }; - - Units.fromRawInputString = function(units) { - try { - Units.createCurrencyUnits(); - } catch (parsingError) {} - - var compatibleUnits = Units.toMathjsCompatibleString(units); - if (compatibleUnits !== '') { - try { - math.unit(compatibleUnits); - } catch (err) { - throw new Error(err); - } - } - return new Units(Units.fromStringToList(units)); - }; - - return Units; - }]); diff --git a/core/templates/dev/head/domain/objects/UnitsObjectFactory.js b/core/templates/dev/head/domain/objects/UnitsObjectFactory.js new file mode 100644 index 000000000000..be5ac4301203 --- /dev/null +++ b/core/templates/dev/head/domain/objects/UnitsObjectFactory.js @@ -0,0 +1,207 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Factory for creating instances of Units domain objects. + */ + +oppia.factory('UnitsObjectFactory', ['CURRENCY_UNITS', + function(CURRENCY_UNITS) { + var Units = function(unitsList) { + this.units = unitsList; + }; + + var isunit = function(unit) { + return !('/*() '.includes(unit)); + }; + + Units.stringToLexical = function(units) { + units += '#'; + var unitList = []; + var unit = ''; + for (var i = 0; i < units.length; i++) { + if ('*/()# '.includes(units[i]) && unit !== 'per') { + if (unit.length > 0) { + if ((unitList.length > 0) && isunit(unitList.slice(-1).pop())) { + unitList.push('*'); + } + unitList.push(unit); + unit = ''; + } + if (!('# '.includes(units[i]))) { + unitList.push(units[i]); + } + } else if (units[i] === ' ' && unit === 'per') { + unitList.push('/'); + unit = ''; + } else { + unit += units[i]; + } + } + return unitList; + }; + + var unitWithMultiplier = function(unitList) { + var multiplier = 1; + var unitsWithMultiplier = []; + var parenthesisStack = []; + + for (var ind = 0; ind < unitList.length; ind++) { + if (unitList[ind] === '/') { + multiplier = -multiplier; + } else if (unitList[ind] === '(') { + if (unitList[ind - 1] === '/') { + // If previous element was division then we need to inverse + // multiplier when we find its corresponsing closing parenthesis. + // Second element of pushed element is used for this purpose. + parenthesisStack.push(['(', -1]); + } else { + // If previous element was not division then we don't need to + // invert the multiplier. + parenthesisStack.push(['(', 1]); + } + } else if (unitList[ind] === ')') { + var elem = parenthesisStack.pop(); + multiplier = parseInt(elem[1]) * multiplier; + } else if (isunit(unitList[ind])) { + unitsWithMultiplier.push([unitList[ind], multiplier]); + // If previous element was division then we need to invert + // multiplier. + if (unitList[ind - 1] === '/') { + multiplier = -multiplier; + } + } + } + return unitsWithMultiplier; + }; + + var convertUnitDictToList = function(unitDict) { + var unitList = []; + for (var key in unitDict) { + unitList.push({unit: key, exponent: unitDict[key]}); + } + return unitList; + }; + + var unitToList = function(unitsWithMultiplier) { + var unitDict = {}; + for (var i = 0; i < unitsWithMultiplier.length; i++) { + var unit = unitsWithMultiplier[i][0]; + var multiplier = unitsWithMultiplier[i][1]; + var ind = unit.indexOf('^'); + var s = null; + var power = null; + if (ind > -1) { + s = unit.substr(0, ind); + power = parseInt(unit.substr(ind + 1)); + } else { + s = unit; + power = 1; + } + if (!(s in unitDict)) { + unitDict[s] = 0; + } + unitDict[s] += multiplier * power; + } + return convertUnitDictToList(unitDict); + }; + + Units.prototype.toDict = function() { + return { + units: this.units + }; + }; + + Units.fromList = function(unitsList) { + return new Units(unitsList); + }; + + Units.fromStringToList = function(unitsString) { + return unitToList(unitWithMultiplier(Units.stringToLexical(unitsString))); + }; + + Units.prototype.toString = function() { + var unit = ''; + for (var i = 0; i < this.units.length; i++) { + var d = this.units[i]; + if (d.exponent === 1) { + unit += d.unit + ' '; + } else { + unit += d.unit + '^' + d.exponent.toString() + ' '; + } + } + return unit.trim(); + }; + + Units.createCurrencyUnits = function() { + // Creates user-defined currency (base + sub) units. + var keys = Object.keys(CURRENCY_UNITS); + for (var i = 0; i < keys.length; i++) { + if (CURRENCY_UNITS[keys[i]].base_unit === null) { + // Base unit (like: rupees, dollar etc.). + math.createUnit(CURRENCY_UNITS[keys[i]].name, { + aliases: CURRENCY_UNITS[keys[i]].aliases}); + } else { + // Sub unit (like: paise, cents etc.). + math.createUnit(CURRENCY_UNITS[keys[i]].name, { + definition: CURRENCY_UNITS[keys[i]].base_unit, + aliases: CURRENCY_UNITS[keys[i]].aliases}); + } + } + }; + + Units.toMathjsCompatibleString = function(units) { + // Makes the units compatible with the math.js allowed format. + units = units.replace(/per/g, '/'); + + // Special symbols need to be replaced as math.js doesn't support custom + // units starting with special symbols. Also, it doesn't allow units + // followed by a number as in the case of currency units. + var keys = Object.keys(CURRENCY_UNITS); + for (var i = 0; i < keys.length; i++) { + for (var j = 0; j < CURRENCY_UNITS[keys[i]].front_units.length; j++) { + if (units.includes(CURRENCY_UNITS[keys[i]].front_units[j])) { + units = units.replace(CURRENCY_UNITS[keys[i]].front_units[j], ''); + units = CURRENCY_UNITS[keys[i]].name + units; + } + } + + for (var j = 0; j < CURRENCY_UNITS[keys[i]].aliases.length; j++) { + if (units.includes(CURRENCY_UNITS[keys[i]].aliases[j])) { + units = units.replace(CURRENCY_UNITS[keys[i]].aliases[j], + CURRENCY_UNITS[keys[i]].name); + } + } + } + return units.trim(); + }; + + Units.fromRawInputString = function(units) { + try { + Units.createCurrencyUnits(); + } catch (parsingError) {} + + var compatibleUnits = Units.toMathjsCompatibleString(units); + if (compatibleUnits !== '') { + try { + math.unit(compatibleUnits); + } catch (err) { + throw new Error(err); + } + } + return new Units(Units.fromStringToList(units)); + }; + + return Units; + }]); diff --git a/core/templates/dev/head/filters/filtersSpec.js b/core/templates/dev/head/filters/filtersSpec.js index f817a3bdad76..3608187ea6a4 100644 --- a/core/templates/dev/head/filters/filtersSpec.js +++ b/core/templates/dev/head/filters/filtersSpec.js @@ -304,13 +304,13 @@ describe('Testing filters', function() { filter('

Text input

') ).toEqual('Text input'); expect( - filter('

Text input

') + filter('

' + + 'Text input

') ).toEqual('[Math] Text input'); expect( filter('

' + - 'Text inputText input 2

') + 'Text input' + + 'Text input 2

') ).toEqual('[Math] Text input [Collapsible] Text input 2'); expect( filter('

' + @@ -320,8 +320,9 @@ describe('Testing filters', function() { ).toEqual('[Math] Text input [Collapsible] Text input 2'); expect( filter('' + - 'Text inputText input 2' + + 'Text input' + + 'Text input 2' + + '' + ' Text Input 3 ') ).toEqual('[Math] Text input [Collapsible] Text input 2 [Image] ' + 'Text Input 3'); diff --git a/core/templates/dev/head/pages/admin/admin.html b/core/templates/dev/head/pages/admin/admin.html index ebfd657457c8..b41e3b147d31 100644 --- a/core/templates/dev/head/pages/admin/admin.html +++ b/core/templates/dev/head/pages/admin/admin.html @@ -70,7 +70,7 @@ {% include 'pages/footer_js_libs.html' %} - + @@ -87,7 +87,7 @@ - + @@ -106,7 +106,16 @@ - + + + + + + + + + + diff --git a/core/templates/dev/head/pages/admin/roles_tab/RolesTabDirective.js b/core/templates/dev/head/pages/admin/roles_tab/AdminRolesTabDirective.js similarity index 100% rename from core/templates/dev/head/pages/admin/roles_tab/RolesTabDirective.js rename to core/templates/dev/head/pages/admin/roles_tab/AdminRolesTabDirective.js diff --git a/core/templates/dev/head/pages/base.html b/core/templates/dev/head/pages/base.html index 812ba80b7c83..8f4ec28c2383 100755 --- a/core/templates/dev/head/pages/base.html +++ b/core/templates/dev/head/pages/base.html @@ -165,8 +165,8 @@

{% include 'pages/footer_js_libs.html' %} - - + + diff --git a/core/templates/dev/head/pages/collection_editor/collection_editor.html b/core/templates/dev/head/pages/collection_editor/collection_editor.html index 3789b7106630..732cd0574f33 100644 --- a/core/templates/dev/head/pages/collection_editor/collection_editor.html +++ b/core/templates/dev/head/pages/collection_editor/collection_editor.html @@ -29,7 +29,7 @@ {% block content %}
- +
@@ -86,11 +86,14 @@ + + + @@ -121,7 +124,16 @@ - + + + + + + + + + + {# TODO(bhenning): Remove these once RouterServices is decoupled from the exploration editor #} @@ -153,7 +165,7 @@ - + diff --git a/core/templates/dev/head/pages/collection_editor/editor_tab/CollectionEditorTabDirective.js b/core/templates/dev/head/pages/collection_editor/editor_tab/CollectionEditorTabDirective.js index fa6cf9718a21..59219f83102a 100644 --- a/core/templates/dev/head/pages/collection_editor/editor_tab/CollectionEditorTabDirective.js +++ b/core/templates/dev/head/pages/collection_editor/editor_tab/CollectionEditorTabDirective.js @@ -16,7 +16,7 @@ * @fileoverview Controller for the main tab of the collection editor. */ -oppia.directive('collectionMainTab', [ +oppia.directive('collectionEditorTab', [ 'UrlInterpolationService', function(UrlInterpolationService) { return { restrict: 'E', diff --git a/core/templates/dev/head/pages/collection_player/collectionFooterDirective.js b/core/templates/dev/head/pages/collection_player/CollectionFooterDirective.js similarity index 100% rename from core/templates/dev/head/pages/collection_player/collectionFooterDirective.js rename to core/templates/dev/head/pages/collection_player/CollectionFooterDirective.js diff --git a/core/templates/dev/head/pages/collection_player/collection_player.html b/core/templates/dev/head/pages/collection_player/collection_player.html index e4dc26b0edf4..f1ecf167c0cc 100644 --- a/core/templates/dev/head/pages/collection_player/collection_player.html +++ b/core/templates/dev/head/pages/collection_player/collection_player.html @@ -398,7 +398,8 @@

- + + diff --git a/core/templates/dev/head/pages/creator_dashboard/creator_dashboard.html b/core/templates/dev/head/pages/creator_dashboard/creator_dashboard.html index 0e166eb21f94..6e9de91ced12 100644 --- a/core/templates/dev/head/pages/creator_dashboard/creator_dashboard.html +++ b/core/templates/dev/head/pages/creator_dashboard/creator_dashboard.html @@ -895,7 +895,16 @@

Suggestions to review

- + + + + + + + + + + @@ -918,33 +927,33 @@

Suggestions to review

- - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -977,6 +986,8 @@

Suggestions to review

+ + @@ -1009,6 +1020,7 @@

Suggestions to review

+ @@ -1053,8 +1065,15 @@

Suggestions to review

- - + + + + + + + + + @@ -1093,7 +1112,7 @@

Suggestions to review

- + diff --git a/core/templates/dev/head/pages/exploration_editor/AngularNameService.js b/core/templates/dev/head/pages/exploration_editor/AngularNameService.js index 8074e2b62b48..2f6eda3869b7 100644 --- a/core/templates/dev/head/pages/exploration_editor/AngularNameService.js +++ b/core/templates/dev/head/pages/exploration_editor/AngularNameService.js @@ -21,7 +21,7 @@ oppia.factory('AngularNameService', [function() { return { getNameOfInteractionRulesService: function(interactionId) { - angularName = interactionId.charAt(0).toLowerCase() + + angularName = interactionId.charAt(0) + interactionId.slice(1) + 'RulesService'; return angularName; } diff --git a/core/templates/dev/head/pages/exploration_editor/AngularNameServiceSpec.js b/core/templates/dev/head/pages/exploration_editor/AngularNameServiceSpec.js index bd9411f6adc2..60d08df4ea87 100644 --- a/core/templates/dev/head/pages/exploration_editor/AngularNameServiceSpec.js +++ b/core/templates/dev/head/pages/exploration_editor/AngularNameServiceSpec.js @@ -28,7 +28,7 @@ describe('Angular names service', function() { it('should map interaction ID to correct RulesService', function() { expect(ans.getNameOfInteractionRulesService('TextInput')).toEqual( - 'textInputRulesService'); + 'TextInputRulesService'); }); }); }); diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/ExplorationEditorTab.js b/core/templates/dev/head/pages/exploration_editor/editor_tab/ExplorationEditorTab.js index f0080e58e97f..b5b87cefe14f 100644 --- a/core/templates/dev/head/pages/exploration_editor/editor_tab/ExplorationEditorTab.js +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/ExplorationEditorTab.js @@ -179,108 +179,3 @@ oppia.controller('ExplorationEditorTab', [ }; } ]); - -oppia.directive('trainingPanel', [ - 'UrlInterpolationService', function(UrlInterpolationService) { - return { - restrict: 'E', - scope: { - answer: '=', - // The classification input is an object with two keys: - // -answerGroupIndex: This refers to which answer group the answer - // being trained has been classified to (for displaying feedback - // to the creator). If answerGroupIndex is equal to the number of - // answer groups, then it represents the default outcome feedback. - // This index is changed by the panel when the creator specifies - // which feedback should be associated with the answer. - // -newOutcome: This refers to an outcome structure (containing a - // list of feedback and a destination state name) which is - // non-null if, and only if, the creator has specified that a new - // response should be created for the trained answer. - classification: '=', - onFinishTraining: '&', - addingNewResponse: '=' - }, - templateUrl: UrlInterpolationService.getDirectiveTemplateUrl( - '/pages/exploration_editor/editor_tab/' + - 'training_answer_modal_directive.html'), - controller: [ - '$scope', 'ExplorationHtmlFormatterService', - 'StateEditorService', 'ExplorationStatesService', - 'TrainingDataService', 'ResponsesService', 'StateInteractionIdService', - 'StateCustomizationArgsService', 'AnswerGroupObjectFactory', - 'OutcomeObjectFactory', 'GenerateContentIdService', - 'COMPONENT_NAME_FEEDBACK', - function( - $scope, ExplorationHtmlFormatterService, - StateEditorService, ExplorationStatesService, - TrainingDataService, ResponsesService, StateInteractionIdService, - StateCustomizationArgsService, AnswerGroupObjectFactory, - OutcomeObjectFactory, GenerateContentIdService, - COMPONENT_NAME_FEEDBACK) { - $scope.addingNewResponse = false; - - var _stateName = StateEditorService.getActiveStateName(); - var _state = ExplorationStatesService.getState(_stateName); - $scope.allOutcomes = TrainingDataService.getAllPotentialOutcomes( - _state); - - var _updateAnswerTemplate = function() { - $scope.answerTemplate = ( - ExplorationHtmlFormatterService.getAnswerHtml( - $scope.answer, StateInteractionIdService.savedMemento, - StateCustomizationArgsService.savedMemento)); - }; - - var _getExistingOutcomeContentIds = function() { - var existingContentIds = []; - $scope.allOutcomes.forEach(function(outcome) { - var contentId = outcome.feedback.getContentId(); - existingContentIds.push(contentId); - }); - return existingContentIds; - }; - - $scope.$watch('answer', _updateAnswerTemplate); - _updateAnswerTemplate(); - $scope.selectedAnswerGroupIndex = ( - $scope.classification.answerGroupIndex); - - $scope.getCurrentStateName = function() { - return StateEditorService.getActiveStateName(); - }; - - $scope.beginAddingNewResponse = function() { - var contentId = GenerateContentIdService.getNextId( - _getExistingOutcomeContentIds(), COMPONENT_NAME_FEEDBACK); - $scope.classification.newOutcome = OutcomeObjectFactory.createNew( - StateEditorService.getActiveStateName(), contentId, '', []); - $scope.addingNewResponse = true; - }; - - $scope.cancelAddingNewResponse = function() { - $scope.addingNewResponse = false; - $scope.classification.newOutcome = null; - }; - - $scope.selectAnswerGroupIndex = function(index) { - $scope.selectedAnswerGroupIndex = index; - $scope.classification.answerGroupIndex = index; - if (index > ResponsesService.getAnswerGroupCount()) { - $scope.classification.newOutcome = $scope.allOutcomes[index]; - } - }; - - $scope.confirmNewFeedback = function() { - if ($scope.classification.newOutcome) { - // Push the new outcome at the end of the existing outcomes. - $scope.allOutcomes.push($scope.classification.newOutcome); - $scope.selectAnswerGroupIndex($scope.allOutcomes.length - 1); - $scope.addingNewResponse = false; - } - }; - } - ] - }; - }] -); diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/StateGraphVisualizationDirective.js b/core/templates/dev/head/pages/exploration_editor/editor_tab/StateGraphVisualizationDirective.js index 2c22f331c043..6d9cca78a579 100644 --- a/core/templates/dev/head/pages/exploration_editor/editor_tab/StateGraphVisualizationDirective.js +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/StateGraphVisualizationDirective.js @@ -17,7 +17,7 @@ */ /* eslint-disable angular/directive-restrict */ -oppia.directive('stateGraphViz', [ +oppia.directive('stateGraphVisualization', [ 'UrlInterpolationService', function(UrlInterpolationService) { return { // Note: This directive is used as attribute because pannability does not diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/TestInteractionPanelDirective.js b/core/templates/dev/head/pages/exploration_editor/editor_tab/TestInteractionPanelDirective.js index c4746bc97fbe..d181f5337633 100644 --- a/core/templates/dev/head/pages/exploration_editor/editor_tab/TestInteractionPanelDirective.js +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/TestInteractionPanelDirective.js @@ -15,6 +15,7 @@ /** * @fileoverview Directive for the test interaction panel in the state editor. */ + oppia.directive('testInteractionPanel', [ 'UrlInterpolationService', function(UrlInterpolationService) { return { diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/TrainingPanelDirective.js b/core/templates/dev/head/pages/exploration_editor/editor_tab/TrainingPanelDirective.js new file mode 100644 index 000000000000..5f426156d994 --- /dev/null +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/TrainingPanelDirective.js @@ -0,0 +1,122 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for the training panel in the state editor. + */ + +oppia.directive('trainingPanel', [ + 'UrlInterpolationService', function(UrlInterpolationService) { + return { + restrict: 'E', + scope: { + answer: '=', + // The classification input is an object with two keys: + // -answerGroupIndex: This refers to which answer group the answer + // being trained has been classified to (for displaying feedback + // to the creator). If answerGroupIndex is equal to the number of + // answer groups, then it represents the default outcome feedback. + // This index is changed by the panel when the creator specifies + // which feedback should be associated with the answer. + // -newOutcome: This refers to an outcome structure (containing a + // list of feedback and a destination state name) which is + // non-null if, and only if, the creator has specified that a new + // response should be created for the trained answer. + classification: '=', + onFinishTraining: '&', + addingNewResponse: '=' + }, + templateUrl: UrlInterpolationService.getDirectiveTemplateUrl( + '/pages/exploration_editor/editor_tab/' + + 'training_answer_modal_directive.html'), + controller: [ + '$scope', 'ExplorationHtmlFormatterService', + 'StateEditorService', 'ExplorationStatesService', + 'TrainingDataService', 'ResponsesService', 'StateInteractionIdService', + 'StateCustomizationArgsService', 'AnswerGroupObjectFactory', + 'OutcomeObjectFactory', 'GenerateContentIdService', + 'COMPONENT_NAME_FEEDBACK', + function( + $scope, ExplorationHtmlFormatterService, + StateEditorService, ExplorationStatesService, + TrainingDataService, ResponsesService, StateInteractionIdService, + StateCustomizationArgsService, AnswerGroupObjectFactory, + OutcomeObjectFactory, GenerateContentIdService, + COMPONENT_NAME_FEEDBACK) { + $scope.addingNewResponse = false; + + var _stateName = StateEditorService.getActiveStateName(); + var _state = ExplorationStatesService.getState(_stateName); + $scope.allOutcomes = TrainingDataService.getAllPotentialOutcomes( + _state); + + var _updateAnswerTemplate = function() { + $scope.answerTemplate = ( + ExplorationHtmlFormatterService.getAnswerHtml( + $scope.answer, StateInteractionIdService.savedMemento, + StateCustomizationArgsService.savedMemento)); + }; + + var _getExistingOutcomeContentIds = function() { + var existingContentIds = []; + $scope.allOutcomes.forEach(function(outcome) { + var contentId = outcome.feedback.getContentId(); + existingContentIds.push(contentId); + }); + return existingContentIds; + }; + + $scope.$watch('answer', _updateAnswerTemplate); + _updateAnswerTemplate(); + $scope.selectedAnswerGroupIndex = ( + $scope.classification.answerGroupIndex); + + $scope.getCurrentStateName = function() { + return StateEditorService.getActiveStateName(); + }; + + $scope.beginAddingNewResponse = function() { + var contentId = GenerateContentIdService.getNextId( + _getExistingOutcomeContentIds(), COMPONENT_NAME_FEEDBACK); + $scope.classification.newOutcome = OutcomeObjectFactory.createNew( + StateEditorService.getActiveStateName(), contentId, '', []); + $scope.addingNewResponse = true; + }; + + $scope.cancelAddingNewResponse = function() { + $scope.addingNewResponse = false; + $scope.classification.newOutcome = null; + }; + + $scope.selectAnswerGroupIndex = function(index) { + $scope.selectedAnswerGroupIndex = index; + $scope.classification.answerGroupIndex = index; + if (index > ResponsesService.getAnswerGroupCount()) { + $scope.classification.newOutcome = $scope.allOutcomes[index]; + } + }; + + $scope.confirmNewFeedback = function() { + if ($scope.classification.newOutcome) { + // Push the new outcome at the end of the existing outcomes. + $scope.allOutcomes.push($scope.classification.newOutcome); + $scope.selectAnswerGroupIndex($scope.allOutcomes.length - 1); + $scope.addingNewResponse = false; + } + }; + } + ] + }; + }] +); diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph.html b/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph.html index a2d918024eac..64b06fb3248f 100644 --- a/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph.html +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph.html @@ -5,7 +5,7 @@
-
+
diff --git a/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph_modal_directive.html b/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph_modal_directive.html index c63920ec7391..9c6ed2462680 100644 --- a/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph_modal_directive.html +++ b/core/templates/dev/head/pages/exploration_editor/editor_tab/exploration_graph_modal_directive.html @@ -3,7 +3,7 @@

Exploration Overview

- +
diff --git a/core/templates/dev/head/pages/exploration_editor/translation_tab/state_translation_status_graph_directive.html b/core/templates/dev/head/pages/exploration_editor/translation_tab/state_translation_status_graph_directive.html index 6ab6324137f0..56eee06ae8df 100644 --- a/core/templates/dev/head/pages/exploration_editor/translation_tab/state_translation_status_graph_directive.html +++ b/core/templates/dev/head/pages/exploration_editor/translation_tab/state_translation_status_graph_directive.html @@ -4,7 +4,7 @@
-
+
diff --git a/core/templates/dev/head/pages/exploration_player/exploration_player.html b/core/templates/dev/head/pages/exploration_player/exploration_player.html index fa4227deda69..940fbca36c9a 100644 --- a/core/templates/dev/head/pages/exploration_player/exploration_player.html +++ b/core/templates/dev/head/pages/exploration_player/exploration_player.html @@ -82,6 +82,9 @@

+ + + @@ -96,10 +99,6 @@

- - - - @@ -166,6 +165,7 @@

+ @@ -223,7 +223,16 @@

- + + + + + + + + + + diff --git a/core/templates/dev/head/pages/maintenance/maintenance.html b/core/templates/dev/head/pages/maintenance/maintenance.html index 22cee049b503..27aa17b8129e 100644 --- a/core/templates/dev/head/pages/maintenance/maintenance.html +++ b/core/templates/dev/head/pages/maintenance/maintenance.html @@ -49,8 +49,8 @@

The Oppia site is temporarily unavailable.

{% include 'pages/footer_js_libs.html' %} - - + + @@ -62,7 +62,16 @@

The Oppia site is temporarily unavailable.

- + + + + + + + + + + diff --git a/core/templates/dev/head/pages/moderator/moderator.html b/core/templates/dev/head/pages/moderator/moderator.html index b9e8443c097d..f5bfd54aa441 100644 --- a/core/templates/dev/head/pages/moderator/moderator.html +++ b/core/templates/dev/head/pages/moderator/moderator.html @@ -106,9 +106,18 @@

Activities to feature in the library

{% block footer_js %} {{ super() }} + + + + + + + + + + - diff --git a/core/templates/dev/head/pages/notifications_dashboard/NotificationsDashboard.js b/core/templates/dev/head/pages/notifications_dashboard/NotificationsDashboard.js index 9de3a8ce01f8..cd3cef080824 100644 --- a/core/templates/dev/head/pages/notifications_dashboard/NotificationsDashboard.js +++ b/core/templates/dev/head/pages/notifications_dashboard/NotificationsDashboard.js @@ -16,7 +16,7 @@ * @fileoverview Data and controllers for the user's notifications dashboard. */ -oppia.controller('DashboardNotifications', [ +oppia.controller('NotificationsDashboard', [ '$http', '$rootScope', '$scope', 'DateTimeFormatService', function($http, $rootScope, $scope, DateTimeFormatService) { $scope.getItemUrl = function(activityId, notificationType) { diff --git a/core/templates/dev/head/pages/notifications_dashboard/notifications_dashboard.html b/core/templates/dev/head/pages/notifications_dashboard/notifications_dashboard.html index 0ec6defa26cd..2b914e6aa599 100644 --- a/core/templates/dev/head/pages/notifications_dashboard/notifications_dashboard.html +++ b/core/templates/dev/head/pages/notifications_dashboard/notifications_dashboard.html @@ -14,7 +14,7 @@ {% endblock navbar_breadcrumb %} {% block content %} -
+

Notifications

Last updated: <[getLocaleAbbreviatedDatetimeString(jobQueuedMsec)]> diff --git a/core/templates/dev/head/pages/skill_editor/skill_editor.html b/core/templates/dev/head/pages/skill_editor/skill_editor.html index 6f580807ec6a..804bfbefa7bb 100644 --- a/core/templates/dev/head/pages/skill_editor/skill_editor.html +++ b/core/templates/dev/head/pages/skill_editor/skill_editor.html @@ -73,7 +73,14 @@ - + + + + + + + + @@ -88,8 +95,7 @@ - - + @@ -113,6 +119,8 @@ + + @@ -160,6 +168,7 @@ + @@ -168,7 +177,16 @@ - + + + + + + + + + + @@ -186,34 +204,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -230,7 +248,7 @@ - + {% include 'components/rich_text_components.html' %} {{ interaction_templates }} {{ visualizations_html }} diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateContentIdsToAudioTranslationsService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateContentIdsToAudioTranslationsService.js new file mode 100644 index 000000000000..9fb75f495b2e --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateContentIdsToAudioTranslationsService.js @@ -0,0 +1,26 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the content ids + * to audio translations. + */ + +oppia.factory('StateContentIdsToAudioTranslationsService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveContentIdsToAudioTranslations'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateContentService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateContentService.js new file mode 100644 index 000000000000..896511a14c9d --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateContentService.js @@ -0,0 +1,26 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current state content. + */ + +// TODO(sll): Add validation. +oppia.factory('StateContentService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveStateContent'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateCustomizationArgsService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateCustomizationArgsService.js new file mode 100644 index 000000000000..655ad6107e00 --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateCustomizationArgsService.js @@ -0,0 +1,28 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current state customization + * args for theinteraction. This is a dict mapping customization arg names + * to dicts of the form {value: customization_arg_value}. + */ + +// TODO(sll): Add validation. +oppia.factory('StateCustomizationArgsService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveInteractionCustomizationArgs'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/StateEditorService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateEditorService.js similarity index 100% rename from core/templates/dev/head/pages/state_editor/StateEditorService.js rename to core/templates/dev/head/pages/state_editor/state_properties/StateEditorService.js diff --git a/core/templates/dev/head/pages/state_editor/StateEditorServiceSpec.js b/core/templates/dev/head/pages/state_editor/state_properties/StateEditorServiceSpec.js similarity index 100% rename from core/templates/dev/head/pages/state_editor/StateEditorServiceSpec.js rename to core/templates/dev/head/pages/state_editor/state_properties/StateEditorServiceSpec.js diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateHintsService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateHintsService.js new file mode 100644 index 000000000000..28ee3d3d6676 --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateHintsService.js @@ -0,0 +1,25 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current interaction hints. + */ + +oppia.factory('StateHintsService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveHints'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateInteractionIdService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateInteractionIdService.js new file mode 100644 index 000000000000..90caa071f30a --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateInteractionIdService.js @@ -0,0 +1,26 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current interaction id. + */ + +// TODO(sll): Add validation. +oppia.factory('StateInteractionIdService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveInteractionId'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateParamChangesService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateParamChangesService.js new file mode 100644 index 000000000000..d25f284aa52a --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateParamChangesService.js @@ -0,0 +1,27 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current list of + * state parameter changes. + */ + +// TODO(sll): Add validation. +oppia.factory('StateParamChangesService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveStateParamChanges'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/state_editor/StatePropertyServices.js b/core/templates/dev/head/pages/state_editor/state_properties/StatePropertyService.js similarity index 65% rename from core/templates/dev/head/pages/state_editor/StatePropertyServices.js rename to core/templates/dev/head/pages/state_editor/state_properties/StatePropertyService.js index c6ace7a74522..984720000c28 100644 --- a/core/templates/dev/head/pages/state_editor/StatePropertyServices.js +++ b/core/templates/dev/head/pages/state_editor/state_properties/StatePropertyService.js @@ -86,74 +86,6 @@ oppia.factory('StatePropertyService', [ } ]); -// A data service that stores the current state content. -// TODO(sll): Add validation. -oppia.factory('StateContentService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveStateContent'; - return child; - } -]); - -// A data service that stores the current list of state parameter changes. -// TODO(sll): Add validation. -oppia.factory('StateParamChangesService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveStateParamChanges'; - return child; - } -]); - -// A data service that stores the current interaction id. -// TODO(sll): Add validation. -oppia.factory('StateInteractionIdService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveInteractionId'; - return child; - } -]); - -// A data service that stores the current state customization args for the -// interaction. This is a dict mapping customization arg names to dicts of the -// form {value: customization_arg_value}. -// TODO(sll): Add validation. -oppia.factory('StateCustomizationArgsService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveInteractionCustomizationArgs'; - return child; - } -]); - -// A data service that stores the current interaction hints. -oppia.factory('StateHintsService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveHints'; - return child; - } -]); - -// A data service that stores the current interaction solution. -oppia.factory('StateSolutionService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveSolution'; - return child; - } -]); - -oppia.factory('StateContentIdsToAudioTranslationsService', [ - 'StatePropertyService', function(StatePropertyService) { - var child = Object.create(StatePropertyService); - child.setterMethodKey = 'saveContentIdsToAudioTranslations'; - return child; - } -]); - oppia.constant('WARNING_TYPES', { // These must be fixed before the exploration can be saved. CRITICAL: 'critical', diff --git a/core/templates/dev/head/pages/state_editor/StatePropertyServicesSpec.js b/core/templates/dev/head/pages/state_editor/state_properties/StatePropertyServiceSpec.js similarity index 100% rename from core/templates/dev/head/pages/state_editor/StatePropertyServicesSpec.js rename to core/templates/dev/head/pages/state_editor/state_properties/StatePropertyServiceSpec.js diff --git a/core/templates/dev/head/pages/state_editor/state_properties/StateSolutionService.js b/core/templates/dev/head/pages/state_editor/state_properties/StateSolutionService.js new file mode 100644 index 000000000000..da5676acc666 --- /dev/null +++ b/core/templates/dev/head/pages/state_editor/state_properties/StateSolutionService.js @@ -0,0 +1,25 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A data service that stores the current interaction solution. + */ + +oppia.factory('StateSolutionService', [ + 'StatePropertyService', function(StatePropertyService) { + var child = Object.create(StatePropertyService); + child.setterMethodKey = 'saveSolution'; + return child; + } +]); diff --git a/core/templates/dev/head/pages/story_editor/story_editor.html b/core/templates/dev/head/pages/story_editor/story_editor.html index f1816c55ab08..34d5076eadae 100644 --- a/core/templates/dev/head/pages/story_editor/story_editor.html +++ b/core/templates/dev/head/pages/story_editor/story_editor.html @@ -37,6 +37,16 @@ + + + + + + + + + + @@ -44,7 +54,6 @@ - @@ -62,9 +71,9 @@ - - - + + + @@ -74,6 +83,8 @@ + + diff --git a/core/templates/dev/head/pages/tests/FormBuilderTestPage.js b/core/templates/dev/head/pages/tests/FormBuilderTestPage.js index 8eb91ec46b5a..83f16c9433a5 100644 --- a/core/templates/dev/head/pages/tests/FormBuilderTestPage.js +++ b/core/templates/dev/head/pages/tests/FormBuilderTestPage.js @@ -16,40 +16,7 @@ * @fileoverview Controllers for the form builder test page. */ -oppia.directive('formOverlay', [ - 'NestedDirectivesRecursionTimeoutPreventionService', - 'UrlInterpolationService', - function( - NestedDirectivesRecursionTimeoutPreventionService, - UrlInterpolationService) { - return { - scope: { - definition: '=', - isDisabled: '&', - savedValue: '=' - }, - templateUrl: UrlInterpolationService.getDirectiveTemplateUrl( - '/pages/tests/form_entry_point_modal_directive.html'), - restrict: 'E', - compile: NestedDirectivesRecursionTimeoutPreventionService.compile, - controller: ['$scope', function($scope) { - $scope.$watch('savedValue', function() { - $scope.localValue = angular.copy($scope.savedValue); - }); - - $scope.submitValue = function() { - $scope.savedValue = angular.copy($scope.localValue); - alert($scope.savedValue); - }; - $scope.cancelEdit = function() { - $scope.localValue = angular.copy($scope.savedValue); - }; - }] - }; - } -]); - -oppia.controller('FormBuilderTests', [ +oppia.controller('FormBuilderTestPage', [ '$scope', function($scope) { $scope.testText = 'abc{{paramUnicode1}}'; diff --git a/core/templates/dev/head/pages/tests/FormOverlayDirective.js b/core/templates/dev/head/pages/tests/FormOverlayDirective.js new file mode 100644 index 000000000000..241fdda5233e --- /dev/null +++ b/core/templates/dev/head/pages/tests/FormOverlayDirective.js @@ -0,0 +1,50 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for form overlay. + */ + +oppia.directive('formOverlay', [ + 'NestedDirectivesRecursionTimeoutPreventionService', + 'UrlInterpolationService', + function( + NestedDirectivesRecursionTimeoutPreventionService, + UrlInterpolationService) { + return { + scope: { + definition: '=', + isDisabled: '&', + savedValue: '=' + }, + templateUrl: UrlInterpolationService.getDirectiveTemplateUrl( + '/pages/tests/form_entry_point_modal_directive.html'), + restrict: 'E', + compile: NestedDirectivesRecursionTimeoutPreventionService.compile, + controller: ['$scope', function($scope) { + $scope.$watch('savedValue', function() { + $scope.localValue = angular.copy($scope.savedValue); + }); + + $scope.submitValue = function() { + $scope.savedValue = angular.copy($scope.localValue); + alert($scope.savedValue); + }; + $scope.cancelEdit = function() { + $scope.localValue = angular.copy($scope.savedValue); + }; + }] + }; + } +]); diff --git a/core/templates/dev/head/pages/tests/form_builder_test_page.html b/core/templates/dev/head/pages/tests/form_builder_test_page.html index 26442ee4dcc1..de2b435bdf23 100644 --- a/core/templates/dev/head/pages/tests/form_builder_test_page.html +++ b/core/templates/dev/head/pages/tests/form_builder_test_page.html @@ -12,7 +12,7 @@ {% endblock header_js %} {% block content %} -
+

Test page for object editors

Editors sharing a common value

@@ -105,7 +105,16 @@
<[form.name]>
{{ super() }} - + + + + + + + + + + @@ -126,6 +135,7 @@
<[form.name]>
+ diff --git a/core/templates/dev/head/pages/topic_editor/main_editor/TopicEditorTabDirective.js b/core/templates/dev/head/pages/topic_editor/main_editor/TopicEditorTabDirective.js index 1443bdbbf763..f81de91c1e03 100644 --- a/core/templates/dev/head/pages/topic_editor/main_editor/TopicEditorTabDirective.js +++ b/core/templates/dev/head/pages/topic_editor/main_editor/TopicEditorTabDirective.js @@ -15,7 +15,7 @@ /** * @fileoverview Controller for the main topic editor. */ -oppia.directive('topicMainEditor', [ +oppia.directive('topicEditorTab', [ 'UrlInterpolationService', function(UrlInterpolationService) { return { restrict: 'E', diff --git a/core/templates/dev/head/pages/topic_editor/topic_editor.html b/core/templates/dev/head/pages/topic_editor/topic_editor.html index 840f8d9349de..368293828847 100644 --- a/core/templates/dev/head/pages/topic_editor/topic_editor.html +++ b/core/templates/dev/head/pages/topic_editor/topic_editor.html @@ -29,7 +29,7 @@ {% block content %}
- +
@@ -48,6 +48,16 @@ . + + + + + + + + + + @@ -69,7 +79,6 @@ - @@ -91,34 +100,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -150,6 +159,8 @@ + + @@ -183,6 +194,7 @@ + @@ -227,8 +239,15 @@ - - + + + + + + + + + @@ -275,7 +294,7 @@ - + {% include 'components/rich_text_components.html' %} {{ interaction_templates }} {{ visualizations_html }} diff --git a/core/templates/dev/head/pages/topic_viewer/TopicViewerNavbarBreadcrumbDirective.js b/core/templates/dev/head/pages/topic_viewer/TopicViewerNavbarBreadcrumbDirective.js index 29795a337b45..9e063d6ba86e 100644 --- a/core/templates/dev/head/pages/topic_viewer/TopicViewerNavbarBreadcrumbDirective.js +++ b/core/templates/dev/head/pages/topic_viewer/TopicViewerNavbarBreadcrumbDirective.js @@ -15,7 +15,7 @@ /** * @fileoverview Directive for the navbar breadcrumb of the topic viewer. */ -oppia.directive('topicsViewerNavbarBreadcrumb', [ +oppia.directive('topicViewerNavbarBreadcrumb', [ 'UrlInterpolationService', function(UrlInterpolationService) { return { restrict: 'E', diff --git a/core/templates/dev/head/pages/topic_viewer/topic_viewer.html b/core/templates/dev/head/pages/topic_viewer/topic_viewer.html index 59ffcd5b2d63..64ee29a297fc 100644 --- a/core/templates/dev/head/pages/topic_viewer/topic_viewer.html +++ b/core/templates/dev/head/pages/topic_viewer/topic_viewer.html @@ -5,8 +5,8 @@ {% endblock maintitle %} {% block navbar_breadcrumb %} - - + + {% endblock navbar_breadcrumb %} {% block content %} diff --git a/core/tests/build_sources/templates/base.html b/core/tests/build_sources/templates/base.html index 4a6c4fb97c7b..dd4c1bb07278 100755 --- a/core/tests/build_sources/templates/base.html +++ b/core/tests/build_sources/templates/base.html @@ -170,8 +170,8 @@

{% include 'pages/footer_js_libs.html' %} - - + + diff --git a/extensions/classifiers/SVMPredictionService.js b/extensions/classifiers/SVMPredictionService.js index bbc36066614b..f56165f7aa53 100644 --- a/extensions/classifiers/SVMPredictionService.js +++ b/extensions/classifiers/SVMPredictionService.js @@ -27,8 +27,8 @@ */ oppia.factory('SVMPredictionService', [ - '$log', 'PredictionResultOjectFactory', - function($log, PredictionResultOjectFactory) { + '$log', 'PredictionResultObjectFactory', + function($log, PredictionResultObjectFactory) { return { kernel: function(kernelParams, supportVectors, input) { var kernel = kernelParams.kernel; @@ -240,7 +240,7 @@ oppia.factory('SVMPredictionService', [ } var predictedLabel = classes[maxProbIdx]; - var prediction = PredictionResultOjectFactory.createNew( + var prediction = PredictionResultObjectFactory.createNew( predictedLabel, probabilities[maxProbIdx]); return prediction; } diff --git a/extensions/interactions/CodeRepl/directives/CodeReplRulesService.js b/extensions/interactions/CodeRepl/directives/CodeReplRulesService.js index b9c373b2e48d..e2431634528e 100644 --- a/extensions/interactions/CodeRepl/directives/CodeReplRulesService.js +++ b/extensions/interactions/CodeRepl/directives/CodeReplRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('codeReplRulesService', [ +oppia.factory('CodeReplRulesService', [ '$filter', 'CodeNormalizerService', function($filter, CodeNormalizerService) { return { diff --git a/extensions/interactions/CodeRepl/directives/CodeReplRulesServiceSpec.js b/extensions/interactions/CodeRepl/directives/CodeReplRulesServiceSpec.js index 91e888dea0db..7c3877aec3d3 100644 --- a/extensions/interactions/CodeRepl/directives/CodeReplRulesServiceSpec.js +++ b/extensions/interactions/CodeRepl/directives/CodeReplRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Code REPL rules service', function() { var crrs = null; beforeEach(inject(function($injector) { - crrs = $injector.get('codeReplRulesService'); + crrs = $injector.get('CodeReplRulesService'); })); describe('\'equals\' rule', function() { diff --git a/extensions/interactions/CodeRepl/directives/OppiaInteractiveCodeReplDirective.js b/extensions/interactions/CodeRepl/directives/OppiaInteractiveCodeReplDirective.js index 03f1b63b7859..cf2b0b012546 100644 --- a/extensions/interactions/CodeRepl/directives/OppiaInteractiveCodeReplDirective.js +++ b/extensions/interactions/CodeRepl/directives/OppiaInteractiveCodeReplDirective.js @@ -21,10 +21,10 @@ */ oppia.directive('oppiaInteractiveCodeRepl', [ - 'HtmlEscaperService', 'UrlInterpolationService', 'codeReplRulesService', + 'CodeReplRulesService', 'HtmlEscaperService', 'UrlInterpolationService', 'EVENT_NEW_CARD_AVAILABLE', function( - HtmlEscaperService, UrlInterpolationService, codeReplRulesService, + CodeReplRulesService, HtmlEscaperService, UrlInterpolationService, EVENT_NEW_CARD_AVAILABLE) { return { restrict: 'E', @@ -242,7 +242,7 @@ oppia.directive('oppiaInteractiveCodeRepl', [ output: $scope.output, evaluation: $scope.evaluation, error: (err || '') - }, codeReplRulesService); + }, CodeReplRulesService); // Without this, the error message displayed in the user-facing // console will sometimes not update. diff --git a/extensions/interactions/Continue/directives/ContinueRulesService.js b/extensions/interactions/Continue/directives/ContinueRulesService.js index 91379cc5be2e..9920b571dd5c 100644 --- a/extensions/interactions/Continue/directives/ContinueRulesService.js +++ b/extensions/interactions/Continue/directives/ContinueRulesService.js @@ -16,6 +16,6 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('continueRulesService', [function() { +oppia.factory('ContinueRulesService', [function() { return {}; }]); diff --git a/extensions/interactions/Continue/directives/OppiaInteractiveContinueDirective.js b/extensions/interactions/Continue/directives/OppiaInteractiveContinueDirective.js index 7cd36ef3f545..984da81a74d1 100644 --- a/extensions/interactions/Continue/directives/OppiaInteractiveContinueDirective.js +++ b/extensions/interactions/Continue/directives/OppiaInteractiveContinueDirective.js @@ -20,8 +20,8 @@ * followed by the name of the arg. */ oppia.directive('oppiaInteractiveContinue', [ - 'HtmlEscaperService', 'UrlInterpolationService', 'continueRulesService', - function(HtmlEscaperService, UrlInterpolationService, continueRulesService) { + 'ContinueRulesService', 'HtmlEscaperService', 'UrlInterpolationService', + function(ContinueRulesService, HtmlEscaperService, UrlInterpolationService) { return { restrict: 'E', scope: {}, @@ -54,7 +54,7 @@ oppia.directive('oppiaInteractiveContinue', [ } CurrentInteractionService.onSubmit( - humanReadableAnswer, continueRulesService); + humanReadableAnswer, ContinueRulesService); }; CurrentInteractionService.registerCurrentInteraction( diff --git a/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesService.js b/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesService.js index 96a0b5d876bb..7c4d9d36b8e1 100644 --- a/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesService.js +++ b/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesService.js @@ -17,7 +17,7 @@ */ // Rules Service for DragAndDropSortInput interaction. -oppia.factory('dragAndDropSortInputRulesService', [function() { +oppia.factory('DragAndDropSortInputRulesService', [function() { var checkEquality = function(answer, inputs) { for (var i = 0; i < answer.length; i++) { if (answer[i].length === inputs.x[i].length) { diff --git a/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesServiceSpec.js b/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesServiceSpec.js index 85350ca1fd63..c9362cd914b4 100644 --- a/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesServiceSpec.js +++ b/extensions/interactions/DragAndDropSortInput/directives/DragAndDropSortInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Drag and Drop Sort Input rules service', function() { var ddsrs = null; beforeEach(inject(function($injector) { - ddsrs = $injector.get('dragAndDropSortInputRulesService'); + ddsrs = $injector.get('DragAndDropSortInputRulesService'); })); it('should have a correct \'is equal to ordering\' rule', function() { diff --git a/extensions/interactions/DragAndDropSortInput/directives/OppiaInteractiveDragAndDropSortInputDirective.js b/extensions/interactions/DragAndDropSortInput/directives/OppiaInteractiveDragAndDropSortInputDirective.js index fdb373fba65c..8090bf60f1ca 100644 --- a/extensions/interactions/DragAndDropSortInput/directives/OppiaInteractiveDragAndDropSortInputDirective.js +++ b/extensions/interactions/DragAndDropSortInput/directives/OppiaInteractiveDragAndDropSortInputDirective.js @@ -77,7 +77,7 @@ oppia.directive('oppiaInteractiveDragAndDropSortInput', [ } CurrentInteractionService.onSubmit( - answers, dragAndDropSortInputRulesService); + answers, DragAndDropSortInputRulesService); }; CurrentInteractionService.registerCurrentInteraction( diff --git a/extensions/interactions/EndExploration/directives/EndExplorationRulesService.js b/extensions/interactions/EndExploration/directives/EndExplorationRulesService.js index cf6ad05ed224..cf7ae45a1fd0 100644 --- a/extensions/interactions/EndExploration/directives/EndExplorationRulesService.js +++ b/extensions/interactions/EndExploration/directives/EndExplorationRulesService.js @@ -16,6 +16,6 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('endExplorationRulesService', [function() { +oppia.factory('EndExplorationRulesService', [function() { return {}; }]); diff --git a/extensions/interactions/FractionInput/directives/FractionInputRulesService.js b/extensions/interactions/FractionInput/directives/FractionInputRulesService.js index b9add3a7aee0..d0bd7bbd8d7b 100644 --- a/extensions/interactions/FractionInput/directives/FractionInputRulesService.js +++ b/extensions/interactions/FractionInput/directives/FractionInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('fractionInputRulesService', [ +oppia.factory('FractionInputRulesService', [ 'FractionObjectFactory', function(FractionObjectFactory) { var toFloat = function(fractionDict) { diff --git a/extensions/interactions/FractionInput/directives/FractionInputRulesServiceSpec.js b/extensions/interactions/FractionInput/directives/FractionInputRulesServiceSpec.js index 19ed98f1c100..fbde91d7067a 100644 --- a/extensions/interactions/FractionInput/directives/FractionInputRulesServiceSpec.js +++ b/extensions/interactions/FractionInput/directives/FractionInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Fraction Input rules service', function() { var firs = null; beforeEach(inject(function($injector) { - firs = $injector.get('fractionInputRulesService'); + firs = $injector.get('FractionInputRulesService'); })); var createNegativeFractionDict = function( diff --git a/extensions/interactions/FractionInput/directives/OppiaInteractiveFractionInputDirective.js b/extensions/interactions/FractionInput/directives/OppiaInteractiveFractionInputDirective.js index 41257aca7b2c..f21f2decfa20 100644 --- a/extensions/interactions/FractionInput/directives/OppiaInteractiveFractionInputDirective.js +++ b/extensions/interactions/FractionInput/directives/OppiaInteractiveFractionInputDirective.js @@ -26,11 +26,11 @@ oppia.directive('oppiaInteractiveFractionInput', [ '/interactions/FractionInput/directives/' + 'fraction_input_interaction_directive.html'), controller: [ - '$scope', '$attrs', 'FocusManagerService', 'fractionInputRulesService', + '$scope', '$attrs', 'FocusManagerService', 'FractionInputRulesService', 'FractionObjectFactory', 'FRACTION_PARSING_ERRORS', 'WindowDimensionsService', 'CurrentInteractionService', function( - $scope, $attrs, FocusManagerService, fractionInputRulesService, + $scope, $attrs, FocusManagerService, FractionInputRulesService, FractionObjectFactory, FRACTION_PARSING_ERRORS, WindowDimensionsService, CurrentInteractionService) { $scope.answer = ''; @@ -121,7 +121,7 @@ oppia.directive('oppiaInteractiveFractionInput', [ FORM_ERROR_TYPE, false); } else { CurrentInteractionService.onSubmit( - fraction, fractionInputRulesService); + fraction, FractionInputRulesService); } } catch (parsingError) { errorMessage = parsingError.message; diff --git a/extensions/interactions/GraphInput/directives/GraphDetailService.js b/extensions/interactions/GraphInput/directives/GraphDetailService.js index 26536ef9b831..657cfe7c62d5 100644 --- a/extensions/interactions/GraphInput/directives/GraphDetailService.js +++ b/extensions/interactions/GraphInput/directives/GraphDetailService.js @@ -16,7 +16,7 @@ * @fileoverview Detail service for the interaction. */ -oppia.factory('graphDetailService', [function() { +oppia.factory('GraphDetailService', [function() { return { VERTEX_RADIUS: 6, EDGE_WIDTH: 3, diff --git a/extensions/interactions/GraphInput/directives/GraphInputRulesService.js b/extensions/interactions/GraphInput/directives/GraphInputRulesService.js index 6b576918bbf4..937885350716 100644 --- a/extensions/interactions/GraphInput/directives/GraphInputRulesService.js +++ b/extensions/interactions/GraphInput/directives/GraphInputRulesService.js @@ -16,8 +16,8 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('graphInputRulesService', [ - 'graphUtilsService', function(graphUtilsService) { +oppia.factory('GraphInputRulesService', [ + 'GraphUtilsService', function(GraphUtilsService) { /** * @param {object} graph - A graph object. * @return {boolean} Whether the graph is strongly connected. @@ -29,15 +29,15 @@ oppia.factory('graphInputRulesService', [ return true; } - var adjacencyLists = graphUtilsService.constructAdjacencyLists( - graph, graphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); - var invertedAdjacencyLists = graphUtilsService.constructAdjacencyLists( - graph, graphUtilsService.GRAPH_ADJACENCY_MODE.INVERTED); + var adjacencyLists = GraphUtilsService.constructAdjacencyLists( + graph, GraphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); + var invertedAdjacencyLists = GraphUtilsService.constructAdjacencyLists( + graph, GraphUtilsService.GRAPH_ADJACENCY_MODE.INVERTED); var isVisited = graph.vertices.map(function() { return false; }); - graphUtilsService.markAccessible(0, adjacencyLists, isVisited); + GraphUtilsService.markAccessible(0, adjacencyLists, isVisited); var isAnyVertexUnreachable = isVisited.some(function(visited) { return visited === false; }); @@ -45,7 +45,7 @@ oppia.factory('graphInputRulesService', [ var isVisitedInReverse = graph.vertices.map(function() { return false; }); - graphUtilsService.markAccessible( + GraphUtilsService.markAccessible( 0, invertedAdjacencyLists, isVisitedInReverse); var isAnyVertexUnreachableInReverse = isVisitedInReverse.some(function(visited) { @@ -66,12 +66,12 @@ oppia.factory('graphInputRulesService', [ return true; } - var adjacencyLists = graphUtilsService.constructAdjacencyLists( - graph, graphUtilsService.GRAPH_ADJACENCY_MODE.UNDIRECTED); + var adjacencyLists = GraphUtilsService.constructAdjacencyLists( + graph, GraphUtilsService.GRAPH_ADJACENCY_MODE.UNDIRECTED); var isVisited = graph.vertices.map(function() { return false; }); - graphUtilsService.markAccessible(0, adjacencyLists, isVisited); + GraphUtilsService.markAccessible(0, adjacencyLists, isVisited); return isVisited.every(function(visited) { return visited === true; }); @@ -86,15 +86,15 @@ oppia.factory('graphInputRulesService', [ // ancestor in the search tree. var isVisited = graph.vertices.map(function() { - return graphUtilsService.DFS_STATUS.UNVISITED; + return GraphUtilsService.DFS_STATUS.UNVISITED; }); - var adjacencyLists = graphUtilsService.constructAdjacencyLists( - graph, graphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); + var adjacencyLists = GraphUtilsService.constructAdjacencyLists( + graph, GraphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); for (var startVertex = 0; startVertex < graph.vertices.length; startVertex++) { - if (isVisited[startVertex] === graphUtilsService.DFS_STATUS.UNVISITED) { - if (graphUtilsService.findCycle( + if (isVisited[startVertex] === GraphUtilsService.DFS_STATUS.UNVISITED) { + if (GraphUtilsService.findCycle( startVertex, -1, adjacencyLists, isVisited, graph.isDirected)) { return false; } @@ -113,8 +113,8 @@ oppia.factory('graphInputRulesService', [ return true; } - var adjacencyLists = graphUtilsService.constructAdjacencyLists( - graph, graphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); + var adjacencyLists = GraphUtilsService.constructAdjacencyLists( + graph, GraphUtilsService.GRAPH_ADJACENCY_MODE.DIRECTED); var outdegreeCounts = adjacencyLists.map(function(list) { return list.length; }); @@ -141,8 +141,8 @@ oppia.factory('graphInputRulesService', [ return false; } - var adj1 = graphUtilsService.constructAdjacencyMatrix(graph1); - var adj2 = graphUtilsService.constructAdjacencyMatrix(graph2); + var adj1 = GraphUtilsService.constructAdjacencyMatrix(graph1); + var adj2 = GraphUtilsService.constructAdjacencyMatrix(graph2); // Check that for every vertex from the first graph there is a vertex in // the second graph with the same sum of weights of outgoing edges @@ -174,11 +174,11 @@ oppia.factory('graphInputRulesService', [ return vertex.label === graph1.vertices[permutation[index]].label; }); if (doLabelsMatch && - graphUtilsService.areAdjacencyMatricesEqualWithPermutation( + GraphUtilsService.areAdjacencyMatricesEqualWithPermutation( adj1, adj2, permutation)) { return true; } - permutation = graphUtilsService.nextPermutation(permutation); + permutation = GraphUtilsService.nextPermutation(permutation); } return false; }; diff --git a/extensions/interactions/GraphInput/directives/GraphInputRulesServiceSpec.js b/extensions/interactions/GraphInput/directives/GraphInputRulesServiceSpec.js index 85cd5d96a4e4..64ce7b90ff5d 100644 --- a/extensions/interactions/GraphInput/directives/GraphInputRulesServiceSpec.js +++ b/extensions/interactions/GraphInput/directives/GraphInputRulesServiceSpec.js @@ -21,13 +21,13 @@ describe('Graph Input service', function() { var girs = null; beforeEach(inject(function($injector) { - girs = $injector.get('graphInputRulesService'); + girs = $injector.get('GraphInputRulesService'); })); describe('graph utilities', function() { var utils = null; beforeEach(inject(function($injector) { - utils = $injector.get('graphUtilsService'); + utils = $injector.get('GraphUtilsService'); })); it('should construct an adjacency matrix from a graph', function() { diff --git a/extensions/interactions/GraphInput/directives/GraphUtilsService.js b/extensions/interactions/GraphInput/directives/GraphUtilsService.js index 5c6e585008a1..e58df6c25bf7 100644 --- a/extensions/interactions/GraphInput/directives/GraphUtilsService.js +++ b/extensions/interactions/GraphInput/directives/GraphUtilsService.js @@ -16,7 +16,7 @@ * @fileoverview Utils service for the interaction. */ -oppia.factory('graphUtilsService', [function() { +oppia.factory('GraphUtilsService', [function() { return { GRAPH_ADJACENCY_MODE: { DIRECTED: 'directed', diff --git a/extensions/interactions/GraphInput/directives/GraphVizDirective.js b/extensions/interactions/GraphInput/directives/GraphVizDirective.js index 2eed080f6e59..d1be818799b2 100644 --- a/extensions/interactions/GraphInput/directives/GraphVizDirective.js +++ b/extensions/interactions/GraphInput/directives/GraphVizDirective.js @@ -41,11 +41,11 @@ oppia.directive('graphViz', [ 'graph_viz_directive.html'), controller: [ '$scope', '$element', '$attrs', '$document', '$timeout', - 'FocusManagerService', 'graphDetailService', 'GRAPH_INPUT_LEFT_MARGIN', + 'FocusManagerService', 'GraphDetailService', 'GRAPH_INPUT_LEFT_MARGIN', 'EVENT_NEW_CARD_AVAILABLE', 'DeviceInfoService', function( $scope, $element, $attrs, $document, $timeout, - FocusManagerService, graphDetailService, GRAPH_INPUT_LEFT_MARGIN, + FocusManagerService, GraphDetailService, GRAPH_INPUT_LEFT_MARGIN, EVENT_NEW_CARD_AVAILABLE, DeviceInfoService) { var _MODES = { MOVE: 0, @@ -79,8 +79,8 @@ oppia.directive('graphViz', [ mouseDragStartY: 0 }; - $scope.VERTEX_RADIUS = graphDetailService.VERTEX_RADIUS; - $scope.EDGE_WIDTH = graphDetailService.EDGE_WIDTH; + $scope.VERTEX_RADIUS = GraphDetailService.VERTEX_RADIUS; + $scope.EDGE_WIDTH = GraphDetailService.EDGE_WIDTH; $scope.selectedEdgeWeightValue = 0; $scope.shouldShowWrongWeightWarning = false; @@ -572,11 +572,11 @@ oppia.directive('graphViz', [ } }; $scope.getDirectedEdgeArrowPoints = function(index) { - return graphDetailService.getDirectedEdgeArrowPoints( + return GraphDetailService.getDirectedEdgeArrowPoints( $scope.graph, index); }; $scope.getEdgeCentre = function(index) { - return graphDetailService.getEdgeCentre($scope.graph, index); + return GraphDetailService.getEdgeCentre($scope.graph, index); }; // Initial value of SVG view box. diff --git a/extensions/interactions/GraphInput/directives/OppiaInteractiveGraphInputDirective.js b/extensions/interactions/GraphInput/directives/OppiaInteractiveGraphInputDirective.js index 95cad9ca1ed8..cac0e09a3322 100644 --- a/extensions/interactions/GraphInput/directives/OppiaInteractiveGraphInputDirective.js +++ b/extensions/interactions/GraphInput/directives/OppiaInteractiveGraphInputDirective.js @@ -23,11 +23,11 @@ oppia.constant('GRAPH_INPUT_LEFT_MARGIN', 120); oppia.directive('oppiaInteractiveGraphInput', [ - 'HtmlEscaperService', 'UrlInterpolationService', 'UrlService', - 'graphInputRulesService', 'EVENT_NEW_CARD_AVAILABLE', + 'GraphInputRulesService', 'HtmlEscaperService', 'UrlInterpolationService', + 'UrlService', 'EVENT_NEW_CARD_AVAILABLE', function( - HtmlEscaperService, UrlInterpolationService, UrlService, - graphInputRulesService, EVENT_NEW_CARD_AVAILABLE) { + GraphInputRulesService, HtmlEscaperService, UrlInterpolationService, + UrlService, EVENT_NEW_CARD_AVAILABLE) { return { restrict: 'E', scope: { @@ -53,7 +53,7 @@ oppia.directive('oppiaInteractiveGraphInput', [ $scope.submitGraph = function() { // Here, angular.copy is needed to strip $$hashkey from the graph. CurrentInteractionService.onSubmit( - angular.copy($scope.graph), graphInputRulesService); + angular.copy($scope.graph), GraphInputRulesService); }; $scope.interactionIsActive = ($scope.getLastAnswer() === null); $scope.$on(EVENT_NEW_CARD_AVAILABLE, function() { diff --git a/extensions/interactions/GraphInput/directives/OppiaResponseGraphInputDirective.js b/extensions/interactions/GraphInput/directives/OppiaResponseGraphInputDirective.js index e0eefcc9288c..9fb119cc1dae 100644 --- a/extensions/interactions/GraphInput/directives/OppiaResponseGraphInputDirective.js +++ b/extensions/interactions/GraphInput/directives/OppiaResponseGraphInputDirective.js @@ -34,17 +34,17 @@ oppia.directive('oppiaResponseGraphInput', [ 'graph_input_response_directive.html'), controller: ['$scope', '$attrs', function($scope, $attrs) { $scope.graph = HtmlEscaperService.escapedJsonToObj($attrs.answer); - $scope.VERTEX_RADIUS = graphDetailService.VERTEX_RADIUS; - $scope.EDGE_WIDTH = graphDetailService.EDGE_WIDTH; + $scope.VERTEX_RADIUS = GraphDetailService.VERTEX_RADIUS; + $scope.EDGE_WIDTH = GraphDetailService.EDGE_WIDTH; $scope.GRAPH_INPUT_LEFT_MARGIN = GRAPH_INPUT_LEFT_MARGIN; $scope.getDirectedEdgeArrowPoints = function(index) { - return graphDetailService.getDirectedEdgeArrowPoints( + return GraphDetailService.getDirectedEdgeArrowPoints( $scope.graph, index); }; $scope.getEdgeCentre = function(index) { - return graphDetailService.getEdgeCentre($scope.graph, index); + return GraphDetailService.getEdgeCentre($scope.graph, index); }; }] }; diff --git a/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesService.js b/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesService.js index 5df7208aa131..f6aafb77ee75 100644 --- a/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesService.js +++ b/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('imageClickInputRulesService', [function() { +oppia.factory('ImageClickInputRulesService', [function() { return { IsInRegion: function(answer, inputs) { return answer.clickedRegions.indexOf(inputs.x) !== -1; diff --git a/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesServiceSpec.js b/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesServiceSpec.js index bfd89cbf2afd..ad104ccf2c54 100644 --- a/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesServiceSpec.js +++ b/extensions/interactions/ImageClickInput/directives/ImageClickInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Image Click Input rules service', function() { var icirs = null; beforeEach(inject(function($injector) { - icirs = $injector.get('imageClickInputRulesService'); + icirs = $injector.get('ImageClickInputRulesService'); })); it('should have a correct \'is in region\' rule', function() { diff --git a/extensions/interactions/ImageClickInput/directives/OppiaInteractiveImageClickInputDirective.js b/extensions/interactions/ImageClickInput/directives/OppiaInteractiveImageClickInputDirective.js index 63dcd159e705..8aaff96c7c25 100644 --- a/extensions/interactions/ImageClickInput/directives/OppiaInteractiveImageClickInputDirective.js +++ b/extensions/interactions/ImageClickInput/directives/OppiaInteractiveImageClickInputDirective.js @@ -189,7 +189,7 @@ oppia.directive('oppiaInteractiveImageClickInput', [ clickedRegions: $scope.currentlyHoveredRegions }; CurrentInteractionService.onSubmit( - answer, imageClickInputRulesService); + answer, ImageClickInputRulesService); }; CurrentInteractionService.registerCurrentInteraction(null, null); diff --git a/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesService.js b/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesService.js index 4c1caa09829a..d6f5674f25b0 100644 --- a/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesService.js +++ b/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('interactiveMapRulesService', [ +oppia.factory('InteractiveMapRulesService', [ function() { var RADIUS_OF_EARTH_KM = 6371.0; var degreesToRadians = function(angle) { diff --git a/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesServiceSpec.js b/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesServiceSpec.js index 5660a3257891..61d1539c8bf7 100644 --- a/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesServiceSpec.js +++ b/extensions/interactions/InteractiveMap/directives/InteractiveMapRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Numeric Input service', function() { var imrs = null; beforeEach(inject(function($injector) { - imrs = $injector.get('interactiveMapRulesService'); + imrs = $injector.get('InteractiveMapRulesService'); })); var RADIUS_OF_EARTH_KM = 6371.0; diff --git a/extensions/interactions/InteractiveMap/directives/OppiaInteractiveInteractiveMapDirective.js b/extensions/interactions/InteractiveMap/directives/OppiaInteractiveInteractiveMapDirective.js index 18fd72c6b544..ae4c3a7a1eed 100644 --- a/extensions/interactions/InteractiveMap/directives/OppiaInteractiveInteractiveMapDirective.js +++ b/extensions/interactions/InteractiveMap/directives/OppiaInteractiveInteractiveMapDirective.js @@ -20,10 +20,10 @@ * followed by the name of the arg. */ oppia.directive('oppiaInteractiveInteractiveMap', [ - 'HtmlEscaperService', 'UrlInterpolationService', 'interactiveMapRulesService', + 'HtmlEscaperService', 'InteractiveMapRulesService', 'UrlInterpolationService', 'EVENT_NEW_CARD_AVAILABLE', function( - HtmlEscaperService, UrlInterpolationService, interactiveMapRulesService, + HtmlEscaperService, InteractiveMapRulesService, UrlInterpolationService, EVENT_NEW_CARD_AVAILABLE) { return { restrict: 'E', @@ -135,7 +135,6 @@ oppia.directive('oppiaInteractiveInteractiveMap', [ $scope.hideOverlay(); } }); - $scope.$on('leafletDirectiveMap.interactiveMap.click', function(evt, args) { if ($scope.interactionIsActive) { @@ -143,10 +142,9 @@ oppia.directive('oppiaInteractiveInteractiveMap', [ var newLng = args.leafletEvent.latlng.lng; changeMarkerPosition(newLat, newLng); CurrentInteractionService.onSubmit( - [newLat, newLng], interactiveMapRulesService); + [newLat, newLng], InteractiveMapRulesService); } }); - refreshMap(); } ] diff --git a/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesService.js b/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesService.js index 6e06d59a94e1..4591e8fd6438 100644 --- a/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesService.js +++ b/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('itemSelectionInputRulesService', ['$filter', function($filter) { +oppia.factory('ItemSelectionInputRulesService', ['$filter', function($filter) { return { Equals: function(answer, inputs) { var normalizedAnswer = $filter('removeDuplicatesInArray')(answer); diff --git a/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesServiceSpec.js b/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesServiceSpec.js index e627eff5e91f..13fa12b78927 100644 --- a/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesServiceSpec.js +++ b/extensions/interactions/ItemSelectionInput/directives/ItemSelectionInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Item Selection rules service', function() { var isirs = null; beforeEach(inject(function($injector) { - isirs = $injector.get('itemSelectionInputRulesService'); + isirs = $injector.get('ItemSelectionInputRulesService'); })); it('should have a correct \'equals\' rule', function() { diff --git a/extensions/interactions/ItemSelectionInput/directives/OppiaInteractiveItemSelectionInputDirective.js b/extensions/interactions/ItemSelectionInput/directives/OppiaInteractiveItemSelectionInputDirective.js index 598afee404f0..36442e236861 100644 --- a/extensions/interactions/ItemSelectionInput/directives/OppiaInteractiveItemSelectionInputDirective.js +++ b/extensions/interactions/ItemSelectionInput/directives/OppiaInteractiveItemSelectionInputDirective.js @@ -90,7 +90,7 @@ oppia.directive('oppiaInteractiveItemSelectionInput', [ ); CurrentInteractionService.onSubmit( - answers, itemSelectionInputRulesService); + answers, ItemSelectionInputRulesService); }; var validityCheckFn = function() { diff --git a/extensions/interactions/LogicProof/directives/LogicProofRulesService.js b/extensions/interactions/LogicProof/directives/LogicProofRulesService.js index e57f4f679589..59804ae45d5f 100644 --- a/extensions/interactions/LogicProof/directives/LogicProofRulesService.js +++ b/extensions/interactions/LogicProof/directives/LogicProofRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('logicProofRulesService', [function() { +oppia.factory('LogicProofRulesService', [function() { return { Correct: function(answer) { return answer.correct; diff --git a/extensions/interactions/LogicProof/directives/LogicProofRulesServiceSpec.js b/extensions/interactions/LogicProof/directives/LogicProofRulesServiceSpec.js index 18ccded10483..deda19dbc05a 100644 --- a/extensions/interactions/LogicProof/directives/LogicProofRulesServiceSpec.js +++ b/extensions/interactions/LogicProof/directives/LogicProofRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Logic Proof rules service', function() { var lprs = null; beforeEach(inject(function($injector) { - lprs = $injector.get('logicProofRulesService'); + lprs = $injector.get('LogicProofRulesService'); })); var CORRECT_EXAMPLE = { diff --git a/extensions/interactions/LogicProof/directives/OppiaInteractiveLogicProofDirective.js b/extensions/interactions/LogicProof/directives/OppiaInteractiveLogicProofDirective.js index ca09c5fda4d3..2daeaa7a5f94 100644 --- a/extensions/interactions/LogicProof/directives/OppiaInteractiveLogicProofDirective.js +++ b/extensions/interactions/LogicProof/directives/OppiaInteractiveLogicProofDirective.js @@ -29,11 +29,11 @@ oppia.directive('oppiaInteractiveLogicProof', [ '/interactions/LogicProof/directives/' + 'logic_proof_interaction_directive.html'), controller: [ - '$scope', '$attrs', '$uibModal', 'logicProofRulesService', + '$scope', '$attrs', '$uibModal', 'LogicProofRulesService', 'WindowDimensionsService', 'UrlService', 'CurrentInteractionService', function( - $scope, $attrs, $uibModal, logicProofRulesService, + $scope, $attrs, $uibModal, LogicProofRulesService, WindowDimensionsService, UrlService, CurrentInteractionService) { $scope.localQuestionData = HtmlEscaperService.escapedJsonToObj( @@ -256,7 +256,7 @@ oppia.directive('oppiaInteractiveLogicProof', [ $scope.proofString); } CurrentInteractionService.onSubmit( - submission, logicProofRulesService); + submission, LogicProofRulesService); }; CurrentInteractionService.registerCurrentInteraction( diff --git a/extensions/interactions/LogicProof/static/js/tools/demonstration.js b/extensions/interactions/LogicProof/static/js/tools/LogicDemoTestController.js similarity index 99% rename from extensions/interactions/LogicProof/static/js/tools/demonstration.js rename to extensions/interactions/LogicProof/static/js/tools/LogicDemoTestController.js index bff8f9ecbd00..3b68d39282e6 100644 --- a/extensions/interactions/LogicProof/static/js/tools/demonstration.js +++ b/extensions/interactions/LogicProof/static/js/tools/LogicDemoTestController.js @@ -14,7 +14,7 @@ var logicDemo = angular.module('logicDemo', []); -logicDemo.controller('TestCtrl', ['$scope', function($scope) { +logicDemo.controller('LogicDemoTestController', ['$scope', function($scope) { $scope.buildIndexer = function(n) { var output = []; for (var i = 0; i < n; i++) { diff --git a/extensions/interactions/LogicProof/static/js/tools/demonstration.html b/extensions/interactions/LogicProof/static/js/tools/demonstration.html index d92618324fae..2c21822b8fb0 100644 --- a/extensions/interactions/LogicProof/static/js/tools/demonstration.html +++ b/extensions/interactions/LogicProof/static/js/tools/demonstration.html @@ -7,11 +7,11 @@ - + - +

Demonstration of the oppia logic interaction.

Student's section

diff --git a/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesService.js b/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesService.js index 4e9edc05c48d..147a8bcebf80 100644 --- a/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesService.js +++ b/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('mathExpressionInputRulesService', [function() { +oppia.factory('MathExpressionInputRulesService', [function() { return { IsMathematicallyEquivalentTo: function(answer, inputs) { return ( diff --git a/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesServiceSpec.js b/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesServiceSpec.js index c7992340dbf3..79a11686f7b5 100644 --- a/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesServiceSpec.js +++ b/extensions/interactions/MathExpressionInput/directives/MathExpressionInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Math expression input rules service', function() { var meirs = null; beforeEach(inject(function($injector) { - meirs = $injector.get('mathExpressionInputRulesService'); + meirs = $injector.get('MathExpressionInputRulesService'); })); it('should have a correct equivalence rule', function() { diff --git a/extensions/interactions/MathExpressionInput/directives/OppiaInteractiveMathExpressionInputDirective.js b/extensions/interactions/MathExpressionInput/directives/OppiaInteractiveMathExpressionInputDirective.js index a588cfd95794..a74112f98544 100644 --- a/extensions/interactions/MathExpressionInput/directives/OppiaInteractiveMathExpressionInputDirective.js +++ b/extensions/interactions/MathExpressionInput/directives/OppiaInteractiveMathExpressionInputDirective.js @@ -20,11 +20,11 @@ * followed by the name of the arg. */ oppia.directive('oppiaInteractiveMathExpressionInput', [ - 'HtmlEscaperService', 'UrlInterpolationService', - 'mathExpressionInputRulesService', + 'HtmlEscaperService', 'MathExpressionInputRulesService', + 'UrlInterpolationService', function( - HtmlEscaperService, UrlInterpolationService, - mathExpressionInputRulesService) { + HtmlEscaperService, MathExpressionInputRulesService, + UrlInterpolationService) { return { restrict: 'E', scope: {}, @@ -205,7 +205,7 @@ oppia.directive('oppiaInteractiveMathExpressionInput', [ answer.latex = guppyInstance.latex(); answer.ascii = guppyInstance.text(); CurrentInteractionService.onSubmit( - answer, mathExpressionInputRulesService); + answer, MathExpressionInputRulesService); }; CurrentInteractionService.registerCurrentInteraction( diff --git a/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesService.js b/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesService.js index 3e2e7d8ed5a4..c2bb6cbae075 100644 --- a/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesService.js +++ b/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('multipleChoiceInputRulesService', [function() { +oppia.factory('MultipleChoiceInputRulesService', [function() { return { Equals: function(answer, inputs) { return answer === inputs.x; diff --git a/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesServiceSpec.js b/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesServiceSpec.js index ecfeacf260f8..3511c5f867e8 100644 --- a/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesServiceSpec.js +++ b/extensions/interactions/MultipleChoiceInput/directives/MultipleChoiceInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Multiple choice input rules service', function() { var mcirs = null; beforeEach(inject(function($injector) { - mcirs = $injector.get('multipleChoiceInputRulesService'); + mcirs = $injector.get('MultipleChoiceInputRulesService'); })); it('should have a correct \'equals\' rule', function() { diff --git a/extensions/interactions/MultipleChoiceInput/directives/OppiaInteractiveMultipleChoiceInputDirective.js b/extensions/interactions/MultipleChoiceInput/directives/OppiaInteractiveMultipleChoiceInputDirective.js index 76020c9ed7c8..c469debc8a91 100644 --- a/extensions/interactions/MultipleChoiceInput/directives/OppiaInteractiveMultipleChoiceInputDirective.js +++ b/extensions/interactions/MultipleChoiceInput/directives/OppiaInteractiveMultipleChoiceInputDirective.js @@ -20,11 +20,11 @@ * followed by the name of the arg. */ oppia.directive('oppiaInteractiveMultipleChoiceInput', [ - 'HtmlEscaperService', 'UrlInterpolationService', - 'multipleChoiceInputRulesService', + 'HtmlEscaperService', 'MultipleChoiceInputRulesService', + 'UrlInterpolationService', function( - HtmlEscaperService, UrlInterpolationService, - multipleChoiceInputRulesService) { + HtmlEscaperService, MultipleChoiceInputRulesService, + UrlInterpolationService) { return { restrict: 'E', scope: {}, @@ -44,7 +44,7 @@ oppia.directive('oppiaInteractiveMultipleChoiceInput', [ } answer = parseInt(answer, 10); CurrentInteractionService.onSubmit( - answer, multipleChoiceInputRulesService); + answer, MultipleChoiceInputRulesService); }; CurrentInteractionService.registerCurrentInteraction(null, null); } diff --git a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesService.js b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesService.js index db6ff84b6840..022be2a5424e 100644 --- a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesService.js +++ b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('musicNotesInputRulesService', [ +oppia.factory('MusicNotesInputRulesService', [ 'NOTE_NAMES_TO_MIDI_VALUES', function(NOTE_NAMES_TO_MIDI_VALUES) { var _getMidiNoteValue = function(note) { if (NOTE_NAMES_TO_MIDI_VALUES.hasOwnProperty(note.readableNoteName)) { diff --git a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesServiceSpec.js b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesServiceSpec.js index d0b16fa8effd..ea568b703308 100644 --- a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesServiceSpec.js +++ b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Music Notes Input rules service', function() { var mnirs = null; beforeEach(inject(function($injector) { - mnirs = $injector.get('musicNotesInputRulesService'); + mnirs = $injector.get('MusicNotesInputRulesService'); })); it('should have a correct \'equals\' rule', function() { diff --git a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputSpec.js b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputSpec.js index fc881dfafa46..666a537b9028 100644 --- a/extensions/interactions/MusicNotesInput/directives/MusicNotesInputSpec.js +++ b/extensions/interactions/MusicNotesInput/directives/MusicNotesInputSpec.js @@ -219,7 +219,7 @@ describe('Music phrase player service', function() { var mpps = null; beforeEach(module('oppia', GLOBALS.TRANSLATOR_PROVIDER_FOR_TESTS)); beforeEach(inject(function($injector, $window) { - mpps = $injector.get('musicPhrasePlayerService'); + mpps = $injector.get('MusicPhrasePlayerService'); // This is here so that, if the test environment is modified // to include MIDI in the future, we will remember to swap // it out with a dummy MIDI and back again after the test. diff --git a/extensions/interactions/MusicNotesInput/directives/MusicPhrasePlayerService.js b/extensions/interactions/MusicNotesInput/directives/MusicPhrasePlayerService.js index ce3e2d1fbfe4..ce0499d3e078 100644 --- a/extensions/interactions/MusicNotesInput/directives/MusicPhrasePlayerService.js +++ b/extensions/interactions/MusicNotesInput/directives/MusicPhrasePlayerService.js @@ -16,7 +16,7 @@ * @fileoverview Player service for the interaction. */ -oppia.factory('musicPhrasePlayerService', ['$timeout', function($timeout) { +oppia.factory('MusicPhrasePlayerService', ['$timeout', function($timeout) { var _MIDI_CHANNEL = 0; var _MIDI_VELOCITY = 127; var _SECS_TO_MILLISECS = 1000.0; diff --git a/extensions/interactions/MusicNotesInput/directives/OppiaInteractiveMusicNotesInputDirective.js b/extensions/interactions/MusicNotesInput/directives/OppiaInteractiveMusicNotesInputDirective.js index 33b3e0b5a38a..5a23c35ed79a 100644 --- a/extensions/interactions/MusicNotesInput/directives/OppiaInteractiveMusicNotesInputDirective.js +++ b/extensions/interactions/MusicNotesInput/directives/OppiaInteractiveMusicNotesInputDirective.js @@ -39,13 +39,13 @@ oppia.constant('NOTE_NAMES_TO_MIDI_VALUES', { oppia.directive('oppiaInteractiveMusicNotesInput', [ 'CurrentInteractionService', 'HtmlEscaperService', + 'MusicNotesInputRulesService', 'MusicPhrasePlayerService', 'UrlInterpolationService', 'WindowDimensionsService', - 'musicNotesInputRulesService', 'musicPhrasePlayerService', 'EVENT_NEW_CARD_AVAILABLE', 'NOTE_NAMES_TO_MIDI_VALUES', function( CurrentInteractionService, HtmlEscaperService, + MusicNotesInputRulesService, MusicPhrasePlayerService, UrlInterpolationService, WindowDimensionsService, - musicNotesInputRulesService, musicPhrasePlayerService, EVENT_NEW_CARD_AVAILABLE, NOTE_NAMES_TO_MIDI_VALUES) { return { restrict: 'E', @@ -734,7 +734,7 @@ oppia.directive('oppiaInteractiveMusicNotesInput', [ } readableSequence = _makeAllNotesHaveDurationOne(readableSequence); CurrentInteractionService.onSubmit( - readableSequence, musicNotesInputRulesService); + readableSequence, MusicNotesInputRulesService); }; CurrentInteractionService.registerCurrentInteraction( @@ -786,7 +786,7 @@ oppia.directive('oppiaInteractiveMusicNotesInput', [ } } - musicPhrasePlayerService.playMusicPhrase(notes); + MusicPhrasePlayerService.playMusicPhrase(notes); }; // A MIDI pitch is the baseNoteMidiNumber of the note plus the offset. diff --git a/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesService.js b/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesService.js index 8da7696fed6b..85053fb7d0fe 100644 --- a/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesService.js +++ b/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesService.js @@ -17,7 +17,7 @@ */ // Rules service for number with units interaction. -oppia.factory('numberWithUnitsRulesService', [ +oppia.factory('NumberWithUnitsRulesService', [ 'FractionObjectFactory', 'NumberWithUnitsObjectFactory', function(FractionObjectFactory, NumberWithUnitsObjectFactory) { try { diff --git a/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesServiceSpec.js b/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesServiceSpec.js index bbe48abb50b7..412ca719ae5b 100644 --- a/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesServiceSpec.js +++ b/extensions/interactions/NumberWithUnits/directives/NumberWithUnitsRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Number with Units rules service', function() { var nurs = null; beforeEach(inject(function($injector) { - nurs = $injector.get('numberWithUnitsRulesService'); + nurs = $injector.get('NumberWithUnitsRulesService'); })); var createFractionDict = function( diff --git a/extensions/interactions/NumberWithUnits/directives/OppiaInteractiveNumberWithUnitsDirective.js b/extensions/interactions/NumberWithUnits/directives/OppiaInteractiveNumberWithUnitsDirective.js index 0f57d26d0918..ba7819fda228 100644 --- a/extensions/interactions/NumberWithUnits/directives/OppiaInteractiveNumberWithUnitsDirective.js +++ b/extensions/interactions/NumberWithUnits/directives/OppiaInteractiveNumberWithUnitsDirective.js @@ -27,10 +27,10 @@ oppia.directive('oppiaInteractiveNumberWithUnits', [ 'number_with_units_interaction_directive.html'), controller: [ '$scope', '$attrs', '$uibModal', 'NumberWithUnitsObjectFactory', - 'numberWithUnitsRulesService', 'NUMBER_WITH_UNITS_PARSING_ERRORS', + 'NumberWithUnitsRulesService', 'NUMBER_WITH_UNITS_PARSING_ERRORS', 'CurrentInteractionService', function( $scope, $attrs, $uibModal, NumberWithUnitsObjectFactory, - numberWithUnitsRulesService, NUMBER_WITH_UNITS_PARSING_ERRORS, + NumberWithUnitsRulesService, NUMBER_WITH_UNITS_PARSING_ERRORS, CurrentInteractionService) { $scope.answer = ''; $scope.labelForFocusTarget = $attrs.labelForFocusTarget || null; @@ -70,7 +70,7 @@ oppia.directive('oppiaInteractiveNumberWithUnits', [ var numberWithUnits = NumberWithUnitsObjectFactory.fromRawInputString(answer); CurrentInteractionService.onSubmit( - numberWithUnits, numberWithUnitsRulesService); + numberWithUnits, NumberWithUnitsRulesService); } catch (parsingError) { errorMessage = parsingError.message; $scope.NumberWithUnitsForm.answer.$setValidity( diff --git a/extensions/interactions/NumericInput/directives/NumericInputRulesService.js b/extensions/interactions/NumericInput/directives/NumericInputRulesService.js index 3b89a5a9e13d..9f3b7ed21164 100644 --- a/extensions/interactions/NumericInput/directives/NumericInputRulesService.js +++ b/extensions/interactions/NumericInput/directives/NumericInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('numericInputRulesService', [function() { +oppia.factory('NumericInputRulesService', [function() { return { Equals: function(answer, inputs) { return answer === inputs.x; diff --git a/extensions/interactions/NumericInput/directives/NumericInputRulesServiceSpec.js b/extensions/interactions/NumericInput/directives/NumericInputRulesServiceSpec.js index ed7c6b1e6504..6522c93aba94 100644 --- a/extensions/interactions/NumericInput/directives/NumericInputRulesServiceSpec.js +++ b/extensions/interactions/NumericInput/directives/NumericInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Numeric Input service', function() { var nirs = null; beforeEach(inject(function($injector) { - nirs = $injector.get('numericInputRulesService'); + nirs = $injector.get('NumericInputRulesService'); })); it('should have a correct equals rule', function() { diff --git a/extensions/interactions/NumericInput/directives/OppiaInteractiveNumericInputDirective.js b/extensions/interactions/NumericInput/directives/OppiaInteractiveNumericInputDirective.js index 445a9749cae0..f9a16aa4ee08 100644 --- a/extensions/interactions/NumericInput/directives/OppiaInteractiveNumericInputDirective.js +++ b/extensions/interactions/NumericInput/directives/OppiaInteractiveNumericInputDirective.js @@ -28,10 +28,10 @@ oppia.directive('oppiaInteractiveNumericInput', [ '/interactions/NumericInput/directives/' + 'numeric_input_interaction_directive.html'), controller: [ - '$scope', '$attrs', 'FocusManagerService', 'numericInputRulesService', + '$scope', '$attrs', 'FocusManagerService', 'NumericInputRulesService', 'WindowDimensionsService', 'CurrentInteractionService', function( - $scope, $attrs, FocusManagerService, numericInputRulesService, + $scope, $attrs, FocusManagerService, NumericInputRulesService, WindowDimensionsService, CurrentInteractionService) { $scope.answer = ''; $scope.labelForFocusTarget = $attrs.labelForFocusTarget || null; @@ -50,7 +50,7 @@ oppia.directive('oppiaInteractiveNumericInput', [ $scope.submitAnswer = function(answer) { if (isAnswerValid()) { CurrentInteractionService.onSubmit( - answer, numericInputRulesService); + answer, NumericInputRulesService); } }; diff --git a/extensions/interactions/PencilCodeEditor/directives/OppiaInteractivePencilCodeEditorDirective.js b/extensions/interactions/PencilCodeEditor/directives/OppiaInteractivePencilCodeEditorDirective.js index 839ab766547d..01066d96144c 100644 --- a/extensions/interactions/PencilCodeEditor/directives/OppiaInteractivePencilCodeEditorDirective.js +++ b/extensions/interactions/PencilCodeEditor/directives/OppiaInteractivePencilCodeEditorDirective.js @@ -34,10 +34,10 @@ oppia.directive('oppiaInteractivePencilCodeEditor', [ 'pencil_code_editor_interaction_directive.html'), controller: [ '$scope', '$attrs', '$element', '$timeout', '$uibModal', - 'FocusManagerService', 'pencilCodeEditorRulesService', + 'FocusManagerService', 'PencilCodeEditorRulesService', 'CurrentInteractionService', function($scope, $attrs, $element, $timeout, $uibModal, - FocusManagerService, pencilCodeEditorRulesService, + FocusManagerService, PencilCodeEditorRulesService, CurrentInteractionService) { $scope.interactionIsActive = ($scope.getLastAnswer() === null); @@ -147,7 +147,7 @@ oppia.directive('oppiaInteractivePencilCodeEditor', [ output: output || '', evaluation: '', error: '' - }, pencilCodeEditorRulesService); + }, PencilCodeEditorRulesService); }, true); }); @@ -166,7 +166,7 @@ oppia.directive('oppiaInteractivePencilCodeEditor', [ output: '', evaluation: '', error: error.message - }, pencilCodeEditorRulesService); + }, PencilCodeEditorRulesService); $timeout(function() { errorIsHappening = false; diff --git a/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesService.js b/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesService.js index 3d8ba8f9738c..0a3cc9aab060 100644 --- a/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesService.js +++ b/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('pencilCodeEditorRulesService', [ +oppia.factory('PencilCodeEditorRulesService', [ '$filter', 'CodeNormalizerService', function($filter, CodeNormalizerService) { return { diff --git a/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesServiceSpec.js b/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesServiceSpec.js index a3419cf2f11c..b333a8509982 100644 --- a/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesServiceSpec.js +++ b/extensions/interactions/PencilCodeEditor/directives/PencilCodeEditorRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Pencil Code Editor rules service', function() { var pcers = null; beforeEach(inject(function($injector) { - pcers = $injector.get('pencilCodeEditorRulesService'); + pcers = $injector.get('PencilCodeEditorRulesService'); })); describe('\'equals\' rule', function() { diff --git a/extensions/interactions/SetInput/directives/OppiaInteractiveSetInputDirective.js b/extensions/interactions/SetInput/directives/OppiaInteractiveSetInputDirective.js index 19b709c8c158..6438b363a106 100644 --- a/extensions/interactions/SetInput/directives/OppiaInteractiveSetInputDirective.js +++ b/extensions/interactions/SetInput/directives/OppiaInteractiveSetInputDirective.js @@ -29,10 +29,10 @@ oppia.directive('oppiaInteractiveSetInput', [ '/interactions/SetInput/directives/' + 'set_input_interaction_directive.html'), controller: [ - '$scope', '$attrs', '$translate', 'setInputRulesService', + '$scope', '$attrs', '$translate', 'SetInputRulesService', 'WindowDimensionsService', 'CurrentInteractionService', function( - $scope, $attrs, $translate, setInputRulesService, + $scope, $attrs, $translate, SetInputRulesService, WindowDimensionsService, CurrentInteractionService) { $scope.schema = { type: 'list', @@ -73,7 +73,7 @@ oppia.directive('oppiaInteractiveSetInput', [ } else { $scope.errorMessage = ''; CurrentInteractionService.onSubmit( - answer, setInputRulesService); + answer, SetInputRulesService); } }; diff --git a/extensions/interactions/SetInput/directives/SetInputRulesService.js b/extensions/interactions/SetInput/directives/SetInputRulesService.js index d2d368a07601..867f4bc53170 100644 --- a/extensions/interactions/SetInput/directives/SetInputRulesService.js +++ b/extensions/interactions/SetInput/directives/SetInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('setInputRulesService', [function() { +oppia.factory('SetInputRulesService', [function() { return { Equals: function(answer, inputs) { return answer.length === inputs.x.length && inputs.x.every(function(val) { diff --git a/extensions/interactions/SetInput/directives/SetInputRulesServiceSpec.js b/extensions/interactions/SetInput/directives/SetInputRulesServiceSpec.js index ab130c70e6b5..d8511c1283a5 100644 --- a/extensions/interactions/SetInput/directives/SetInputRulesServiceSpec.js +++ b/extensions/interactions/SetInput/directives/SetInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Set Input rules service', function() { var sirs = null; beforeEach(inject(function($injector) { - sirs = $injector.get('setInputRulesService'); + sirs = $injector.get('SetInputRulesService'); })); var RULE_INPUT = { diff --git a/extensions/interactions/TextInput/directives/OppiaInteractiveTextInputDirective.js b/extensions/interactions/TextInput/directives/OppiaInteractiveTextInputDirective.js index 9f92ff5cddea..fc66bdb4bdfa 100644 --- a/extensions/interactions/TextInput/directives/OppiaInteractiveTextInputDirective.js +++ b/extensions/interactions/TextInput/directives/OppiaInteractiveTextInputDirective.js @@ -29,10 +29,10 @@ oppia.directive('oppiaInteractiveTextInput', [ '/interactions/TextInput/directives/' + 'text_input_interaction_directive.html'), controller: [ - '$scope', '$attrs', 'FocusManagerService', 'textInputRulesService', + '$scope', '$attrs', 'FocusManagerService', 'TextInputRulesService', 'WindowDimensionsService', 'CurrentInteractionService', function( - $scope, $attrs, FocusManagerService, textInputRulesService, + $scope, $attrs, FocusManagerService, TextInputRulesService, WindowDimensionsService, CurrentInteractionService) { $scope.placeholder = HtmlEscaperService.escapedJsonToObj( $attrs.placeholderWithValue); @@ -57,7 +57,7 @@ oppia.directive('oppiaInteractiveTextInput', [ return; } - CurrentInteractionService.onSubmit(answer, textInputRulesService); + CurrentInteractionService.onSubmit(answer, TextInputRulesService); }; var submitAnswerFn = function() { diff --git a/extensions/interactions/TextInput/directives/TextInputRulesService.js b/extensions/interactions/TextInput/directives/TextInputRulesService.js index 717165198ba3..0911ac125627 100644 --- a/extensions/interactions/TextInput/directives/TextInputRulesService.js +++ b/extensions/interactions/TextInput/directives/TextInputRulesService.js @@ -16,7 +16,7 @@ * @fileoverview Rules service for the interaction. */ -oppia.factory('textInputRulesService', ['$filter', function($filter) { +oppia.factory('TextInputRulesService', ['$filter', function($filter) { return { Equals: function(answer, inputs) { var normalizedAnswer = $filter('normalizeWhitespace')(answer); diff --git a/extensions/interactions/TextInput/directives/TextInputRulesServiceSpec.js b/extensions/interactions/TextInput/directives/TextInputRulesServiceSpec.js index 6edd7c359b10..a7b740fe7203 100644 --- a/extensions/interactions/TextInput/directives/TextInputRulesServiceSpec.js +++ b/extensions/interactions/TextInput/directives/TextInputRulesServiceSpec.js @@ -21,7 +21,7 @@ describe('Text Input rules service', function() { var tirs = null; beforeEach(inject(function($injector) { - tirs = $injector.get('textInputRulesService'); + tirs = $injector.get('TextInputRulesService'); })); var RULE_INPUT = { diff --git a/extensions/interactions/baseValidator.js b/extensions/interactions/baseInteractionValidationService.js similarity index 100% rename from extensions/interactions/baseValidator.js rename to extensions/interactions/baseInteractionValidationService.js diff --git a/extensions/interactions/base_test.py b/extensions/interactions/base_test.py index bbc72b6aa84c..c5360805c415 100644 --- a/extensions/interactions/base_test.py +++ b/extensions/interactions/base_test.py @@ -394,7 +394,7 @@ def test_default_interactions_are_valid(self): short_response_directive_js_file_content) self.assertIn( '%sRulesService' % ( - interaction_id[0].lower() + interaction_id[1:]), + interaction_id[0] + interaction_id[1:]), rules_service_js_file_content) self.assertIn( '%sValidationService' % interaction_id, diff --git a/extensions/interactions/rulesSpec.js b/extensions/interactions/rulesSpec.js index 1fae5d570ecb..ab945f0956ea 100644 --- a/extensions/interactions/rulesSpec.js +++ b/extensions/interactions/rulesSpec.js @@ -26,7 +26,7 @@ describe('Rule spec services', function() { var getRulesServiceName = function(interactionId) { return ( - interactionId[0].toLowerCase() + interactionId.substr(1) + 'RulesService' + interactionId + 'RulesService' ); }; diff --git a/extensions/objects/templates/BooleanEditor.js b/extensions/objects/templates/BooleanEditorDirective.js similarity index 100% rename from extensions/objects/templates/BooleanEditor.js rename to extensions/objects/templates/BooleanEditorDirective.js diff --git a/extensions/objects/templates/CodeStringEditor.js b/extensions/objects/templates/CodeStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/CodeStringEditor.js rename to extensions/objects/templates/CodeStringEditorDirective.js diff --git a/extensions/objects/templates/CoordTwoDimEditor.js b/extensions/objects/templates/CoordTwoDimEditorDirective.js similarity index 100% rename from extensions/objects/templates/CoordTwoDimEditor.js rename to extensions/objects/templates/CoordTwoDimEditorDirective.js diff --git a/extensions/objects/templates/DragAndDropHtmlStringEditor.js b/extensions/objects/templates/DragAndDropHtmlStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/DragAndDropHtmlStringEditor.js rename to extensions/objects/templates/DragAndDropHtmlStringEditorDirective.js diff --git a/extensions/objects/templates/DragAndDropPositiveIntEditor.js b/extensions/objects/templates/DragAndDropPositiveIntEditorDirective.js similarity index 100% rename from extensions/objects/templates/DragAndDropPositiveIntEditor.js rename to extensions/objects/templates/DragAndDropPositiveIntEditorDirective.js diff --git a/extensions/objects/templates/FilepathEditor.js b/extensions/objects/templates/FilepathEditorDirective.js similarity index 100% rename from extensions/objects/templates/FilepathEditor.js rename to extensions/objects/templates/FilepathEditorDirective.js diff --git a/extensions/objects/templates/FractionEditor.js b/extensions/objects/templates/FractionEditorDirective.js similarity index 100% rename from extensions/objects/templates/FractionEditor.js rename to extensions/objects/templates/FractionEditorDirective.js diff --git a/extensions/objects/templates/GraphEditor.js b/extensions/objects/templates/GraphEditorDirective.js similarity index 100% rename from extensions/objects/templates/GraphEditor.js rename to extensions/objects/templates/GraphEditorDirective.js diff --git a/extensions/objects/templates/GraphPropertyEditor.js b/extensions/objects/templates/GraphPropertyEditorDirective.js similarity index 100% rename from extensions/objects/templates/GraphPropertyEditor.js rename to extensions/objects/templates/GraphPropertyEditorDirective.js diff --git a/extensions/objects/templates/HtmlEditor.js b/extensions/objects/templates/HtmlEditorDirective.js similarity index 100% rename from extensions/objects/templates/HtmlEditor.js rename to extensions/objects/templates/HtmlEditorDirective.js diff --git a/extensions/objects/templates/ImageWithRegionsEditor.js b/extensions/objects/templates/ImageWithRegionsEditorDirective.js similarity index 100% rename from extensions/objects/templates/ImageWithRegionsEditor.js rename to extensions/objects/templates/ImageWithRegionsEditorDirective.js diff --git a/extensions/objects/templates/IntEditor.js b/extensions/objects/templates/IntEditorDirective.js similarity index 100% rename from extensions/objects/templates/IntEditor.js rename to extensions/objects/templates/IntEditorDirective.js diff --git a/extensions/objects/templates/ListOfSetsOfHtmlStringsEditor.js b/extensions/objects/templates/ListOfSetsOfHtmlStringsEditorDirective.js similarity index 100% rename from extensions/objects/templates/ListOfSetsOfHtmlStringsEditor.js rename to extensions/objects/templates/ListOfSetsOfHtmlStringsEditorDirective.js diff --git a/extensions/objects/templates/ListOfTabsEditor.js b/extensions/objects/templates/ListOfTabsEditorDirective.js similarity index 100% rename from extensions/objects/templates/ListOfTabsEditor.js rename to extensions/objects/templates/ListOfTabsEditorDirective.js diff --git a/extensions/objects/templates/ListOfUnicodeStringEditor.js b/extensions/objects/templates/ListOfUnicodeStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/ListOfUnicodeStringEditor.js rename to extensions/objects/templates/ListOfUnicodeStringEditorDirective.js diff --git a/extensions/objects/templates/LogicErrorCategoryEditor.js b/extensions/objects/templates/LogicErrorCategoryEditorDirective.js similarity index 100% rename from extensions/objects/templates/LogicErrorCategoryEditor.js rename to extensions/objects/templates/LogicErrorCategoryEditorDirective.js diff --git a/extensions/objects/templates/LogicQuestionEditor.js b/extensions/objects/templates/LogicQuestionEditorDirective.js similarity index 100% rename from extensions/objects/templates/LogicQuestionEditor.js rename to extensions/objects/templates/LogicQuestionEditorDirective.js diff --git a/extensions/objects/templates/MathLatexStringEditor.js b/extensions/objects/templates/MathLatexStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/MathLatexStringEditor.js rename to extensions/objects/templates/MathLatexStringEditorDirective.js diff --git a/extensions/objects/templates/MusicPhraseEditor.js b/extensions/objects/templates/MusicPhraseEditorDirective.js similarity index 100% rename from extensions/objects/templates/MusicPhraseEditor.js rename to extensions/objects/templates/MusicPhraseEditorDirective.js diff --git a/extensions/objects/templates/NonnegativeIntEditor.js b/extensions/objects/templates/NonnegativeIntEditorDirective.js similarity index 100% rename from extensions/objects/templates/NonnegativeIntEditor.js rename to extensions/objects/templates/NonnegativeIntEditorDirective.js diff --git a/extensions/objects/templates/NormalizedStringEditor.js b/extensions/objects/templates/NormalizedStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/NormalizedStringEditor.js rename to extensions/objects/templates/NormalizedStringEditorDirective.js diff --git a/extensions/objects/templates/NumberWithUnitsEditor.js b/extensions/objects/templates/NumberWithUnitsEditorDirective.js similarity index 100% rename from extensions/objects/templates/NumberWithUnitsEditor.js rename to extensions/objects/templates/NumberWithUnitsEditorDirective.js diff --git a/extensions/objects/templates/ParameterNameEditor.js b/extensions/objects/templates/ParameterNameEditorDirective.js similarity index 100% rename from extensions/objects/templates/ParameterNameEditor.js rename to extensions/objects/templates/ParameterNameEditorDirective.js diff --git a/extensions/objects/templates/RealEditor.js b/extensions/objects/templates/RealEditorDirective.js similarity index 100% rename from extensions/objects/templates/RealEditor.js rename to extensions/objects/templates/RealEditorDirective.js diff --git a/extensions/objects/templates/SanitizedUrlEditor.js b/extensions/objects/templates/SanitizedUrlEditorDirective.js similarity index 100% rename from extensions/objects/templates/SanitizedUrlEditor.js rename to extensions/objects/templates/SanitizedUrlEditorDirective.js diff --git a/extensions/objects/templates/SetOfHtmlStringEditor.js b/extensions/objects/templates/SetOfHtmlStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/SetOfHtmlStringEditor.js rename to extensions/objects/templates/SetOfHtmlStringEditorDirective.js diff --git a/extensions/objects/templates/SetOfUnicodeStringEditor.js b/extensions/objects/templates/SetOfUnicodeStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/SetOfUnicodeStringEditor.js rename to extensions/objects/templates/SetOfUnicodeStringEditorDirective.js diff --git a/extensions/objects/templates/UnicodeStringEditor.js b/extensions/objects/templates/UnicodeStringEditorDirective.js similarity index 100% rename from extensions/objects/templates/UnicodeStringEditor.js rename to extensions/objects/templates/UnicodeStringEditorDirective.js diff --git a/extensions/rich_text_components/Collapsible/directives/CollapsibleDirective.js b/extensions/rich_text_components/Collapsible/directives/OppiaNoninteractiveCollapsibleDirective.js similarity index 100% rename from extensions/rich_text_components/Collapsible/directives/CollapsibleDirective.js rename to extensions/rich_text_components/Collapsible/directives/OppiaNoninteractiveCollapsibleDirective.js diff --git a/extensions/rich_text_components/Image/directives/ImageDirective.js b/extensions/rich_text_components/Image/directives/OppiaNoninteractiveImageDirective.js similarity index 100% rename from extensions/rich_text_components/Image/directives/ImageDirective.js rename to extensions/rich_text_components/Image/directives/OppiaNoninteractiveImageDirective.js diff --git a/extensions/rich_text_components/Link/directives/LinkDirective.js b/extensions/rich_text_components/Link/directives/OppiaNoninteractiveLinkDirective.js similarity index 100% rename from extensions/rich_text_components/Link/directives/LinkDirective.js rename to extensions/rich_text_components/Link/directives/OppiaNoninteractiveLinkDirective.js diff --git a/extensions/rich_text_components/Math/directives/MathDirective.js b/extensions/rich_text_components/Math/directives/OppiaNoninteractiveMathDirective.js similarity index 100% rename from extensions/rich_text_components/Math/directives/MathDirective.js rename to extensions/rich_text_components/Math/directives/OppiaNoninteractiveMathDirective.js diff --git a/extensions/rich_text_components/Tabs/directives/TabsDirective.js b/extensions/rich_text_components/Tabs/directives/OppiaNoninteractiveTabsDirective.js similarity index 100% rename from extensions/rich_text_components/Tabs/directives/TabsDirective.js rename to extensions/rich_text_components/Tabs/directives/OppiaNoninteractiveTabsDirective.js diff --git a/extensions/rich_text_components/Video/directives/VideoDirective.js b/extensions/rich_text_components/Video/directives/OppiaNoninteractiveVideoDirective.js similarity index 100% rename from extensions/rich_text_components/Video/directives/VideoDirective.js rename to extensions/rich_text_components/Video/directives/OppiaNoninteractiveVideoDirective.js diff --git a/extensions/value_generators/templates/Copier.js b/extensions/value_generators/templates/CopierDirective.js similarity index 100% rename from extensions/value_generators/templates/Copier.js rename to extensions/value_generators/templates/CopierDirective.js diff --git a/extensions/value_generators/templates/RandomSelector.js b/extensions/value_generators/templates/RandomSelectorDirective.js similarity index 100% rename from extensions/value_generators/templates/RandomSelector.js rename to extensions/value_generators/templates/RandomSelectorDirective.js diff --git a/extensions/visualizations/visualizations.js b/extensions/visualizations/OppiaVisualizationBarChartDirective.js similarity index 51% rename from extensions/visualizations/visualizations.js rename to extensions/visualizations/OppiaVisualizationBarChartDirective.js index 15c12e4141fe..eb5bb6462590 100644 --- a/extensions/visualizations/visualizations.js +++ b/extensions/visualizations/OppiaVisualizationBarChartDirective.js @@ -13,7 +13,7 @@ // limitations under the License. /** - * @fileoverview Directives for all reusable data visualization components. + * @fileoverview Directive for "bar chart" visualization. */ // Each visualization receives three variables: 'data', 'options', and @@ -61,51 +61,3 @@ oppia.directive('oppiaVisualizationBarChart', [function() { ] }; }]); - -oppia.directive('oppiaVisualizationFrequencyTable', [ - 'UrlInterpolationService', function(UrlInterpolationService) { - return { - restrict: 'E', - scope: {}, - templateUrl: UrlInterpolationService.getExtensionResourceUrl( - '/visualizations/frequency_table_directive.html'), - controller: [ - '$scope', '$attrs', 'HtmlEscaperService', - function($scope, $attrs, HtmlEscaperService) { - $scope.data = HtmlEscaperService.escapedJsonToObj($attrs.escapedData); - $scope.options = - HtmlEscaperService.escapedJsonToObj($attrs.escapedOptions); - $scope.addressedInfoIsSupported = $attrs.addressedInfoIsSupported; - } - ] - }; - } -]); - -oppia.directive('oppiaVisualizationEnumeratedFrequencyTable', [ - 'UrlInterpolationService', function(UrlInterpolationService) { - return { - restrict: 'E', - scope: {}, - templateUrl: UrlInterpolationService.getExtensionResourceUrl( - '/visualizations/enumerated_frequency_table_directive.html'), - controller: [ - '$scope', '$attrs', 'HtmlEscaperService', - function($scope, $attrs, HtmlEscaperService) { - $scope.data = HtmlEscaperService.escapedJsonToObj($attrs.escapedData); - $scope.options = - HtmlEscaperService.escapedJsonToObj($attrs.escapedOptions); - $scope.addressedInfoIsSupported = $attrs.addressedInfoIsSupported; - - $scope.answerVisible = $scope.data.map(function(_, i) { - // First element is shown while all others are hidden by default. - return i === 0; - }); - $scope.toggleAnswerVisibility = function(i) { - $scope.answerVisible[i] = !$scope.answerVisible[i]; - }; - } - ] - }; - } -]); diff --git a/extensions/visualizations/OppiaVisualizationEnumeratedFrequencyTableDirective.js b/extensions/visualizations/OppiaVisualizationEnumeratedFrequencyTableDirective.js new file mode 100644 index 000000000000..7e34dd58802f --- /dev/null +++ b/extensions/visualizations/OppiaVisualizationEnumeratedFrequencyTableDirective.js @@ -0,0 +1,49 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for "enumerated frequency table" visualization. + */ + +// Each visualization receives three variables: 'data', 'options', and +// 'isAddressed'. The exact format for each of these is specific to the +// particular visualization. + +oppia.directive('oppiaVisualizationEnumeratedFrequencyTable', [ + 'UrlInterpolationService', function(UrlInterpolationService) { + return { + restrict: 'E', + scope: {}, + templateUrl: UrlInterpolationService.getExtensionResourceUrl( + '/visualizations/enumerated_frequency_table_directive.html'), + controller: [ + '$scope', '$attrs', 'HtmlEscaperService', + function($scope, $attrs, HtmlEscaperService) { + $scope.data = HtmlEscaperService.escapedJsonToObj($attrs.escapedData); + $scope.options = + HtmlEscaperService.escapedJsonToObj($attrs.escapedOptions); + $scope.addressedInfoIsSupported = $attrs.addressedInfoIsSupported; + + $scope.answerVisible = $scope.data.map(function(_, i) { + // First element is shown while all others are hidden by default. + return i === 0; + }); + $scope.toggleAnswerVisibility = function(i) { + $scope.answerVisible[i] = !$scope.answerVisible[i]; + }; + } + ] + }; + } +]); diff --git a/extensions/visualizations/OppiaVisualizationFrequencyTableDirective.js b/extensions/visualizations/OppiaVisualizationFrequencyTableDirective.js new file mode 100644 index 000000000000..15ce59fb39e7 --- /dev/null +++ b/extensions/visualizations/OppiaVisualizationFrequencyTableDirective.js @@ -0,0 +1,41 @@ +// Copyright 2019 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for the "frequency table" visualization. + */ + +// Each visualization receives three variables: 'data', 'options', and +// 'isAddressed'. The exact format for each of these is specific to the +// particular visualization. + +oppia.directive('oppiaVisualizationFrequencyTable', [ + 'UrlInterpolationService', function(UrlInterpolationService) { + return { + restrict: 'E', + scope: {}, + templateUrl: UrlInterpolationService.getExtensionResourceUrl( + '/visualizations/frequency_table_directive.html'), + controller: [ + '$scope', '$attrs', 'HtmlEscaperService', + function($scope, $attrs, HtmlEscaperService) { + $scope.data = HtmlEscaperService.escapedJsonToObj($attrs.escapedData); + $scope.options = + HtmlEscaperService.escapedJsonToObj($attrs.escapedOptions); + $scope.addressedInfoIsSupported = $attrs.addressedInfoIsSupported; + } + ] + }; + } +]); diff --git a/feconf.py b/feconf.py index 0defa0298d80..db6b948d54cf 100644 --- a/feconf.py +++ b/feconf.py @@ -760,7 +760,7 @@ def get_empty_ratings(): TOP_UNRESOLVED_ANSWERS_COUNT_DASHBOARD = 3 # Number of open feedback to be displayed in the dashboard for each exploration. OPEN_FEEDBACK_COUNT_DASHBOARD = 3 -# NOTE TO DEVELOPERS: This should be synchronized with app.js. +# NOTE TO DEVELOPERS: This should be synchronized with App.js. ENABLE_ML_CLASSIFIERS = False SHOW_COLLECTION_NAVIGATION_TAB_HISTORY = False SHOW_COLLECTION_NAVIGATION_TAB_STATS = False diff --git a/scripts/build_test.py b/scripts/build_test.py index ac77b9c2f602..cfca9a185544 100644 --- a/scripts/build_test.py +++ b/scripts/build_test.py @@ -218,8 +218,8 @@ def test_process_html(self): minified_html_file_stream = StringIO.StringIO() # Obtain actual file hashes of /templates to add hash to all filepaths # within the HTML file. The end result will look like: - # E.g - # --> . + # E.g + # --> . # Only need to hash Base.js. with self.swap(build, 'FILE_EXTENSIONS_TO_IGNORE', ('.html',)): file_hashes = build.get_file_hashes(MOCK_TEMPLATES_DEV_DIR) diff --git a/scripts/pre_commit_linter.py b/scripts/pre_commit_linter.py index 02f14073a143..bd2dba42cb03 100644 --- a/scripts/pre_commit_linter.py +++ b/scripts/pre_commit_linter.py @@ -416,6 +416,54 @@ def _is_filepath_excluded_for_bad_patterns_check(pattern, filepath): or filepath in BAD_PATTERNS[pattern]['excluded_files']) +def _get_expression_from_node_if_one_exists( + parsed_node, components_to_check): + """This function first checks whether the parsed node represents + the required angular component that needs to be derived by checking if + its in the 'components_to_check' list. If yes, then it will return the + expression part of the node from which the component can be derived. + If no, it will return None. It is done by filtering out + 'AssignmentExpression' (as it represents an assignment) and 'Identifier' + (as it represents a static expression). + + Args: + parsed_node: dict. Parsed node of the body of a JS file. + components_to_check: list(str). List of angular components to check + in a JS file. These include directives, factories, controllers, + etc. + + Returns: + expression: dict or None. Expression part of the node if the node + represents a component else None. + """ + if parsed_node.type != 'ExpressionStatement': + return + # Separate the expression part of the node which is the actual + # content of the node. + expression = parsed_node.expression + # Check whether the expression belongs to a + # 'CallExpression' which always contains a call + # and not an 'AssignmentExpression'. + # For example, func() is a CallExpression. + if expression.type != 'CallExpression': + return + # Check whether the expression belongs to a 'MemberExpression' which + # represents a computed expression or an Identifier which represents + # a static expression. + # For example, 'thing.func' is a MemberExpression where + # 'thing' is the object of the MemberExpression and + # 'func' is the property of the MemberExpression. + # Another example of a MemberExpression within a CallExpression is + # 'thing.func()' where 'thing.func' is the callee of the CallExpression. + if expression.callee.type != 'MemberExpression': + return + # Get the component in the JS file. + component = expression.callee.property.name + if component not in components_to_check: + return + return expression + + def _get_changed_filepaths(): """Returns a list of modified files (both staged and unstaged) @@ -1071,12 +1119,13 @@ def _check_directive_scope(self): print '----------------------------------------' # Select JS files which need to be checked. files_to_check = [ - filepath for filepath in self.all_filepaths if ( - filepath.endswith('.js')) - and not any(fnmatch.fnmatch(filepath, pattern) for pattern in - EXCLUDED_PATHS)] + filepath for filepath in self.all_filepaths if + filepath.endswith('.js') and not + any(fnmatch.fnmatch(filepath, pattern) for pattern in + EXCLUDED_PATHS)] failed = False summary_messages = [] + components_to_check = ['directive'] for filepath in files_to_check: parsed_script = self.parsed_js_files[filepath] @@ -1084,23 +1133,9 @@ def _check_directive_scope(self): # Parse the body of the content as nodes. parsed_nodes = parsed_script.body for parsed_node in parsed_nodes: - # Check the type of the node. - if parsed_node.type != 'ExpressionStatement': - continue - # Separate the expression part of the node. - expression = parsed_node.expression - # Check whether the expression belongs to a directive. - expression_type_is_not_call = ( - expression.type != 'CallExpression') - if expression_type_is_not_call: - continue - expression_callee_type_is_not_member = ( - expression.callee.type != 'MemberExpression') - if expression_callee_type_is_not_member: - continue - expression_callee_property_name_is_not_directive = ( - expression.callee.property.name != 'directive') - if expression_callee_property_name_is_not_directive: + expression = _get_expression_from_node_if_one_exists( + parsed_node, components_to_check) + if not expression: continue # Separate the arguments of the expression. arguments = expression.arguments @@ -1130,11 +1165,13 @@ def _check_directive_scope(self): # statement. body_element_type_is_not_return = ( body_element.type != 'ReturnStatement') - body_element_arg_type_is_not_object = ( + body_element_argument_type_is_not_object = ( body_element.argument.type != ( 'ObjectExpression')) - if (body_element_type_is_not_return or ( - body_element_arg_type_is_not_object)): + if ( + body_element_argument_type_is_not_object + or ( + body_element_type_is_not_return)): continue # Separate the properties of the return node. return_node_properties = ( @@ -1157,11 +1194,9 @@ def _check_directive_scope(self): # check if it is an Object Expression. # If it is not, then check for scope: # true and report the error message. - scope_value = ( - return_node_property.value) - if scope_value.type == ( - 'Literal') and ( - scope_value.value): + scope_value = return_node_property.value + if scope_value.type == 'Literal' and ( + scope_value.value): failed = True print ( 'Please ensure that %s ' @@ -1178,8 +1213,8 @@ def _check_directive_scope(self): failed = True print ( 'Please ensure that %s ' - 'directive in %s file ' - 'has a scope: {}.' % ( + 'directive in %s file has a ' + 'scope: {}.' % ( directive_name, filepath)) print '' @@ -1196,8 +1231,94 @@ def _check_directive_scope(self): summary_messages.append(summary_message) print '' + return summary_messages - return summary_messages + def _check_js_component_name_and_count(self): + """This function ensures that all JS files have exactly + one component and and that the name of the component + matches the filename. + """ + if self.verbose_mode_enabled: + print 'Starting js component name and count check' + print '----------------------------------------' + # Select JS files which need to be checked. + files_to_check = [ + filepath for filepath in self.all_filepaths if not + any(fnmatch.fnmatch(filepath, pattern) for pattern in + EXCLUDED_PATHS) + and filepath.endswith('.js') and not filepath.endswith('App.js')] + failed = False + summary_messages = [] + component_name = '' + components_to_check = ['controller', 'directive', 'factory', 'filter'] + for filepath in files_to_check: + component_num = 0 + # Filename without its path and extension. + exact_filename = filepath.split('/')[-1][:-3] + parsed_script = self.parsed_js_files[filepath] + with _redirect_stdout(_TARGET_STDOUT): + # Parse the body of the content as nodes. + parsed_nodes = parsed_script.body + for parsed_node in parsed_nodes: + expression = _get_expression_from_node_if_one_exists( + parsed_node, components_to_check) + if not expression: + continue + component_num += 1 + # Check if the number of components in each file exceeds + # one. + if component_num > 1: + print ( + '%s -> Please ensure that there is exactly one ' + 'component in the file.' % (filepath)) + failed = True + break + # Separate the arguments of the expression. + arguments = expression.arguments + # The first argument of the expression is the + # name of the component. + component_name = arguments[0].value + component = expression.callee.property.name + + # If the component is directive or filter and its name is + # xxx then the filename containing it should be + # XxxDirective.js or XxxFilter.js respectively. + if component == 'directive' or component == 'filter': + if (component_name[0].swapcase() + component_name[1:] + + component.capitalize() != (exact_filename)): + print ( + '%s -> Please ensure that the %s name ' + 'matches the filename' + % (filepath, component)) + failed = True + # If the component is controller or factory, then the + # component name should exactly match the filename + # containing it. If the component's name is xxx then the + # filename should be xxx.js. + else: + if component_name != exact_filename: + print ( + '%s -> Please ensure that the %s name ' + 'matches the filename' + % (filepath, component)) + failed = True + + with _redirect_stdout(_TARGET_STDOUT): + if failed: + summary_message = ( + '%s Js component name and count check failed' % + (_MESSAGE_TYPE_FAILED)) + print summary_message + summary_messages.append(summary_message) + else: + summary_message = ( + '%s Js component name and count check passed' % + (_MESSAGE_TYPE_SUCCESS)) + print summary_message + summary_messages.append(summary_message) + + print '' + return summary_messages def _check_sorted_dependencies(self): """This function checks that the dependencies which are @@ -1208,13 +1329,12 @@ def _check_sorted_dependencies(self): if self.verbose_mode_enabled: print 'Starting sorted dependencies check' print '----------------------------------------' - files_to_check = [ - filepath for filepath in self.all_filepaths if ( - filepath.endswith('.js')) - and not any(fnmatch.fnmatch(filepath, pattern) for pattern in - EXCLUDED_PATHS)] - properties_to_check = ['controller', 'directive', 'factory'] + filepath for filepath in self.all_filepaths if + filepath.endswith('.js') and not + any(fnmatch.fnmatch(filepath, pattern) for pattern in + EXCLUDED_PATHS)] + components_to_check = ['controller', 'directive', 'factory'] failed = False summary_messages = [] @@ -1223,16 +1343,11 @@ def _check_sorted_dependencies(self): with _redirect_stdout(_TARGET_STDOUT): parsed_nodes = parsed_script.body for parsed_node in parsed_nodes: - if parsed_node.type != 'ExpressionStatement': - continue - expression = parsed_node.expression - if expression.type != 'CallExpression': - continue - if expression.callee.type != 'MemberExpression': - continue - property_name = expression.callee.property.name - if property_name not in properties_to_check: + expression = _get_expression_from_node_if_one_exists( + parsed_node, components_to_check) + if not expression: continue + # Separate the arguments of the expression. arguments = expression.arguments if arguments[0].type == 'Literal': property_value = str(arguments[0].value) @@ -1938,6 +2053,7 @@ def perform_all_lint_checks(self): """ linter_messages = self._lint_all_files() + js_component_messages = self._check_js_component_name_and_count() directive_scope_messages = self._check_directive_scope() sorted_dependencies_messages = ( self._check_sorted_dependencies()) @@ -1957,8 +2073,8 @@ def perform_all_lint_checks(self): copyright_notice_messages = ( self._check_for_copyright_notice()) all_messages = ( - directive_scope_messages + sorted_dependencies_messages + - controller_dependency_messages + + js_component_messages + directive_scope_messages + + sorted_dependencies_messages + controller_dependency_messages + html_directive_name_messages + import_order_messages + docstring_messages + comment_messages + html_tag_and_attribute_messages +