diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py
index 3b17daa830..9db91496be 100644
--- a/common/lib/capa/capa/responsetypes.py
+++ b/common/lib/capa/capa/responsetypes.py
@@ -36,7 +36,7 @@ from datetime import datetime
from .util import *
from lxml import etree
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
-import capa.xqueue_interface
+import capa.xqueue_interface as xqueue_interface
log = logging.getLogger(__name__)
diff --git a/common/lib/xmodule/xmodule/templates.py b/common/lib/xmodule/xmodule/templates.py
index f4e37ab0d5..6479b3df24 100644
--- a/common/lib/xmodule/xmodule/templates.py
+++ b/common/lib/xmodule/xmodule/templates.py
@@ -4,8 +4,18 @@ These templates are used by the CMS to provide baseline content that
can be cloned when adding new modules to a course.
`Template`s are defined in x_module. They contain 3 attributes:
- metadata: A dictionary with the template metadata
- data: A JSON value that defines the template content
+ metadata: A dictionary with the template metadata. This should contain
+ any values for fields
+ * with scope Scope.settings
+ * that have values different than the field defaults
+ * and that are to be editable in Studio
+ data: A JSON value that defines the template content. This should be a dictionary
+ containing values for fields
+ * with scope Scope.content
+ * that have values different than the field defaults
+ * and that are to be editable in Studio
+ or, if the module uses a single Scope.content String field named `data`, this
+ should be a string containing the contents of that field
children: A list of Location urls that define the template children
Templates are defined on XModuleDescriptor types, in the template attribute.
diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py
index aca1259ed5..440da8b887 100644
--- a/common/lib/xmodule/xmodule/word_cloud_module.py
+++ b/common/lib/xmodule/xmodule/word_cloud_module.py
@@ -11,6 +11,7 @@ import logging
from pkg_resources import resource_string
from xmodule.raw_module import RawDescriptor
+from xmodule.editing_module import MetadataOnlyEditingDescriptor
from xmodule.x_module import XModule
from xblock.core import Scope, String, Object, Boolean, List, Integer
@@ -19,8 +20,13 @@ log = logging.getLogger(__name__)
def pretty_bool(value):
- BOOL_DICT = [True, "True", "true", "T", "t", "1"]
- return value in BOOL_DICT
+ """Check value for possible `True` value.
+
+ Using this function we can manage different type of Boolean value
+ in xml files.
+ """
+ bool_dict = [True, "True", "true", "T", "t", "1"]
+ return value in bool_dict
class WordCloudFields(object):
@@ -227,9 +233,8 @@ class WordCloudModule(WordCloudFields, XModule):
return self.content
-class WordCloudDescriptor(WordCloudFields, RawDescriptor):
+class WordCloudDescriptor(MetadataOnlyEditingDescriptor, RawDescriptor, WordCloudFields):
"""Descriptor for WordCloud Xmodule."""
module_class = WordCloudModule
template_dir_name = 'word_cloud'
stores_state = True
- mako_template = "widgets/raw-edit.html"
diff --git a/common/static/sass/_mixins.scss b/common/static/sass/_mixins.scss
index 493555b879..6e1a34aaaa 100644
--- a/common/static/sass/_mixins.scss
+++ b/common/static/sass/_mixins.scss
@@ -1,34 +1,80 @@
// studio - utilities - mixins and extends
// ====================
-// font-sizing
-@function em($pxval, $base: 16) {
- @return #{$pxval / $base}em;
-}
-
+// mixins - font sizing
@mixin font-size($sizeValue: 16){
font-size: $sizeValue + px;
font-size: ($sizeValue/10) + rem;
}
-// ====================
-
-// line-height
-@function lh($amount: 1) {
- @return $body-line-height * $amount;
+// mixins - line height
+@mixin lh($fontSize: auto){
+ line-height: ($fontSize*1.48) + px;
+ line-height: (($fontSize/10)*1.48) + rem;
}
// ====================
-// image-replacement hidden text
-@mixin text-hide() {
+// mixins - sizing
+@mixin size($width: $baseline, $height: $baseline) {
+ height: $height;
+ width: $width;
+}
+
+// mixins - sizing
+@mixin square($size: $baseline) {
+ @include size($size);
+}
+
+
+// ====================
+
+// mixins - placeholder styling
+@mixin placeholder($color) {
+ :-moz-placeholder {
+ color: $color;
+ }
+ ::-webkit-input-placeholder {
+ color: $color;
+ }
+ :-ms-input-placeholder {
+ color: $color;
+ }
+}
+
+// ====================
+
+// extends - layout
+
+// used for page/view-level wrappers (for centering/grids)
+.wrapper {
+ @include clearfix();
+ @include box-sizing(border-box);
+ width: 100%;
+}
+
+// removes list styling/spacing when using uls, ols for navigation and less content-centric cases
+.no-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ text-indent: 0;
+
+ li {
+ margin: 0;
+ padding: 0;
+ }
+}
+
+// extends - image-replacement hidden text
+.text-hide {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
-// hidden elems - screenreaders
-@mixin text-sr() {
+// extends - hidden elems - screenreaders
+.text-sr {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
@@ -39,144 +85,107 @@
width: 1px;
}
-// ====================
-
-// vertical and horizontal centering
-@mixin vertically-and-horizontally-centered ($height, $width) {
- left: 50%;
- margin-left: -$width / 2;
- //margin-top: -$height / 2;
- min-height: $height;
- min-width: $width;
- position: absolute;
- top: 150px;
+// extends - wrapping
+.text-wrap {
+ text-wrap: wrap;
+ white-space: pre-wrap;
+ white-space: -moz-pre-wrap;
+ word-wrap: break-word;
}
+// extends - visual link
+.fake-link {
+ cursor: pointer;
+}
+
+// extends - functional disable
+.disabled {
+ pointer-events: none;
+ outline: none;
+}
+
+// extends - depth levels
+.depth0 { z-index: 0; }
+.depth1 { z-index: 10; }
+.depth2 { z-index: 100; }
+.depth3 { z-index: 1000; }
+.depth4 { z-index: 10000; }
+.depth5 { z-index: 100000; }
+
// ====================
-// sizing
-@mixin size($width: $baseline, $height: $baseline) {
- height: $height;
- width: $width;
-}
-
-@mixin square($size: $baseline) {
- @include size($size);
-}
-
-// ====================
-
-// placeholder styling
-@mixin placeholder($color) {
- :-moz-placeholder {
- color: $color;
- }
- ::-webkit-input-placeholder {
- color: $color;
- }
- :-ms-input-placeholder {
- color: $color;
- }
-}
-
-// ====================
-
-// extends - visual
-.faded-hr-divider {
- @include background-image(linear-gradient(180deg, rgba(200,200,200, 0) 0%,
- rgba(200,200,200, 1) 50%,
- rgba(200,200,200, 0)));
- height: 1px;
- width: 100%;
-}
-
-.faded-hr-divider-medium {
- @include background-image(linear-gradient(180deg, rgba(240,240,240, 0) 0%,
- rgba(240,240,240, 1) 50%,
- rgba(240,240,240, 0)));
- height: 1px;
- width: 100%;
-}
-
-.faded-hr-divider-light {
- @include background-image(linear-gradient(180deg, rgba(255,255,255, 0) 0%,
- rgba(255,255,255, 0.8) 50%,
- rgba(255,255,255, 0)));
- height: 1px;
- width: 100%;
-}
-
-.faded-vertical-divider {
- @include background-image(linear-gradient(90deg, rgba(200,200,200, 0) 0%,
- rgba(200,200,200, 1) 50%,
- rgba(200,200,200, 0)));
- height: 100%;
- width: 1px;
-}
-
-.faded-vertical-divider-light {
- @include background-image(linear-gradient(90deg, rgba(255,255,255, 0) 0%,
- rgba(255,255,255, 0.6) 50%,
- rgba(255,255,255, 0)));
- height: 100%;
- width: 1px;
-}
-
-.vertical-divider {
- @extend .faded-vertical-divider;
- position: relative;
-
- &::after {
- @extend .faded-vertical-divider-light;
- content: "";
- display: block;
- position: absolute;
- left: 1px;
- }
-}
-
-.horizontal-divider {
- border: none;
- @extend .faded-hr-divider;
- position: relative;
-
- &::after {
- @extend .faded-hr-divider-light;
- content: "";
- display: block;
- position: absolute;
- top: 1px;
- }
-}
-
-.fade-right-hr-divider {
- @include background-image(linear-gradient(180deg, rgba(200,200,200, 0) 0%,
- rgba(200,200,200, 1)));
- border: none;
-}
-
-.fade-left-hr-divider {
- @include background-image(linear-gradient(180deg, rgba(200,200,200, 1) 0%,
- rgba(200,200,200, 0)));
- border: none;
-}
-
-// extends - ui
-.window {
- @include clearfix();
- @include border-radius(3px);
- @include box-shadow(0 1px 1px $shadow-l1);
- margin-bottom: $baseline;
- border: 1px solid $gray-l2;
- background: $white;
-}
-
-.elem-d1 {
- @include clearfix();
+// extends - buttons
+.btn {
@include box-sizing(border-box);
+ @include transition(color 0.25s ease-in-out, border-color 0.25s ease-in-out, background 0.25s ease-in-out, box-shadow 0.25s ease-in-out);
+ display: inline-block;
+ cursor: pointer;
+
+ &:hover, &:active {
+
+ }
+
+ &.disabled, &[disabled] {
+ cursor: default;
+ pointer-events: none;
+ opacity: 0.5;
+ }
+
+ .icon-inline {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: ($baseline/4);
+ }
}
-.elem-d2 {
- @include clearfix();
- @include box-sizing(border-box);
-}
\ No newline at end of file
+// pill button
+.btn-pill {
+ @include border-radius($baseline/5);
+}
+
+.btn-rounded {
+ @include border-radius($baseline/2);
+}
+
+// primary button
+.btn-primary {
+ @extend .btn;
+ @extend .btn-pill;
+ padding:($baseline/2) $baseline;
+ border-width: 1px;
+ border-style: solid;
+ line-height: 1.5em;
+ text-align: center;
+
+ &:hover, &:active {
+ @include box-shadow(0 2px 1px $shadow-l1);
+ }
+
+ &.current, &.active {
+ @include box-shadow(inset 1px 1px 2px $shadow-d1);
+
+ &:hover, &:active {
+ @include box-shadow(inset 1px 1px 1px $shadow-d1);
+ }
+ }
+}
+
+// secondary button
+.btn-secondary {
+ @extend .btn;
+ @extend .btn-pill;
+ border-width: 1px;
+ border-style: solid;
+ padding:($baseline/2) $baseline;
+ background: transparent;
+ line-height: 1.5em;
+ text-align: center;
+
+ &:hover, &:active {
+
+ }
+
+ &.current, &.active {
+
+ }
+}
diff --git a/doc/public/course_data_formats/word_cloud/word_cloud.rst b/doc/public/course_data_formats/word_cloud/word_cloud.rst
index 32212510c1..5c3d31e149 100644
--- a/doc/public/course_data_formats/word_cloud/word_cloud.rst
+++ b/doc/public/course_data_formats/word_cloud/word_cloud.rst
@@ -18,12 +18,23 @@ The following attributes can be specified for this tag::
[display_name| AUTOGENERATE] – Display name of xmodule. When this attribute is not defined - display name autogenerate with some hash.
[num_inputs| 5] – Number of inputs.
[num_top_words| 250] – Number of max words, which will be displayed.
- [display_student_percents| True] – Display usage percents for each word.
+ [display_student_percents| True] – Display usage percents for each word on the same line together with words.
+
+.. note::
+
+ Percent is shown always when mouse over the word in cloud.
+
+.. note::
+
+ Possible answer for boolean type attributes:
+ True – "True", "true", "T", "t", "1"
+ False – "False", "false", "F", "f", "0"
.. note::
If you want to use the same word cloud (the same storage of words), you must use the same display_name value.
+
Code Example
============
diff --git a/jenkins/base.sh b/jenkins/base.sh
deleted file mode 100644
index 7eb4802b8f..0000000000
--- a/jenkins/base.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-##
-## requires >= 1.3.0 of the Jenkins git plugin
-##
-
-function github_status {
-
- if [[ ! ${GIT_URL} =~ git@github.com:([^/]+)/([^\.]+).git ]]; then
- echo "Cannot parse Github org or repo from URL, using defaults."
- ORG="edx"
- REPO="mitx"
- else
- ORG=${BASH_REMATCH[1]}
- REPO=${BASH_REMATCH[2]}
- fi
-
- gcli status create $ORG $REPO $GIT_COMMIT \
- --params=$1 \
- target_url:$BUILD_URL \
- description:"Build #$BUILD_NUMBER is running" \
- -f csv
-}
-
-function github_mark_failed_on_exit {
- trap '[ $? == "0" ] || github_status state:failed' EXIT
-}
diff --git a/jenkins/test.sh b/jenkins/test.sh
index a90cc8e806..0dfa5dc23d 100755
--- a/jenkins/test.sh
+++ b/jenkins/test.sh
@@ -3,8 +3,21 @@
set -e
set -x
+##
+## requires >= 1.3.0 of the Jenkins git plugin
+##
+
function github_status {
- gcli status create edx edx-platform $GIT_COMMIT \
+ if [[ ! ${GIT_URL} =~ git@github.com:([^/]+)/([^\.]+).git ]]; then
+ echo "Cannot parse Github org or repo from URL, using defaults."
+ ORG="edx"
+ REPO="edx-platform"
+ else
+ ORG=${BASH_REMATCH[1]}
+ REPO=${BASH_REMATCH[2]}
+ fi
+
+ gcli status create $ORG $REPO $GIT_COMMIT \
--params=$1 \
target_url:$BUILD_URL \
description:"Build #$BUILD_NUMBER $2" \
@@ -27,13 +40,29 @@ git submodule foreach 'git reset --hard HEAD'
export PYTHONIOENCODING=UTF-8
GIT_BRANCH=${GIT_BRANCH/HEAD/master}
-if [ ! -d /mnt/virtualenvs/"$JOB_NAME" ]; then
- mkdir -p /mnt/virtualenvs/"$JOB_NAME"
- virtualenv /mnt/virtualenvs/"$JOB_NAME"
+
+# When running in parallel on jenkins, workspace could be suffixed by @x
+# In that case, we want to use a separate virtualenv that matches up with
+# workspace
+#
+# We need to handle both the case of /path/to/workspace
+# and /path/to/workspace@2, which is why we use the following substitutions
+#
+# $WORKSPACE is the absolute path for the workspace
+WORKSPACE_SUFFIX=$(expr "$WORKSPACE" : '.*\(@.*\)') || true
+
+VIRTUALENV_DIR="/mnt/virtualenvs/${JOB_NAME}${WORKSPACE_SUFFIX}"
+
+if [ ! -d "$VIRTUALENV_DIR" ]; then
+ mkdir -p "$VIRTUALENV_DIR"
+ virtualenv "$VIRTUALENV_DIR"
fi
export PIP_DOWNLOAD_CACHE=/mnt/pip-cache
+# Allow django liveserver tests to use a range of ports
+export DJANGO_LIVE_TEST_SERVER_ADDRESS=${DJANGO_LIVE_TEST_SERVER_ADDRESS-localhost:8000-9000}
+
source /mnt/virtualenvs/"$JOB_NAME"/bin/activate
pip install -q -r pre-requirements.txt
yes w | pip install -q -r requirements.txt
diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py
index 235f7d60bb..d50e0b4526 100644
--- a/lms/djangoapps/courseware/tests/tests.py
+++ b/lms/djangoapps/courseware/tests/tests.py
@@ -631,8 +631,8 @@ class TestViewAuth(LoginEnrollmentTestCase):
urls = reverse_urls(['info', 'progress'], course)
urls.extend([
reverse('book', kwargs={'course_id': course.id,
- 'book_index': book.title})
- for book in course.textbooks
+ 'book_index': index})
+ for index, book in enumerate(course.textbooks)
])
return urls
@@ -643,8 +643,6 @@ class TestViewAuth(LoginEnrollmentTestCase):
"""
urls = reverse_urls(['about_course'], course)
urls.append(reverse('courses'))
- # Need separate test for change_enrollment, since it's a POST view
- #urls.append(reverse('change_enrollment'))
return urls
diff --git a/lms/lib/comment_client/utils.py b/lms/lib/comment_client/utils.py
index 53bdd462ad..1ce03ed3c7 100644
--- a/lms/lib/comment_client/utils.py
+++ b/lms/lib/comment_client/utils.py
@@ -1,3 +1,4 @@
+from dogapi import dog_stats_api
import json
import logging
import requests
@@ -30,12 +31,18 @@ def merge_dict(dic1, dic2):
def perform_request(method, url, data_or_params=None, *args, **kwargs):
if data_or_params is None:
data_or_params = {}
+ tags = [
+ "{k}:{v}".format(k=k, v=v)
+ for (k, v) in data_or_params.items() + [("method", method), ("url", url)]
+ if k != 'api_key'
+ ]
data_or_params['api_key'] = settings.API_KEY
try:
- if method in ['post', 'put', 'patch']:
- response = requests.request(method, url, data=data_or_params, timeout=5)
- else:
- response = requests.request(method, url, params=data_or_params, timeout=5)
+ with dog_stats_api.timer('comment_client.request.time', tags=tags):
+ if method in ['post', 'put', 'patch']:
+ response = requests.request(method, url, data=data_or_params, timeout=5)
+ else:
+ response = requests.request(method, url, params=data_or_params, timeout=5)
except Exception as err:
# remove API key if it is in the params
if 'api_key' in data_or_params: