def _localizable(self, value): unit = None if self._precision is not None: precision = self._precision elif value % 1 == 0: value = int(value) if self._abbreviate: for (amount, u) in self._UNITS: # Prefer 1,234,000 over 1.234 mil. and abbreviate only when there are # at most 2 significant digits, such as 1.23 mil. This does not apply # for higher levels, so 1.234 bil. is better than 1,234 mil. precision = 2 if amount == 10 ** 6 else 3 if value >= amount and value % (amount / 10 ** precision) == 0: value /= float(amount) unit = u while precision and int((10 ** precision) * value) % 10 == 0: precision -= 1 break else: precision = 0 else: precision = 0 else: precision = 2 result = self._LOCALIZABLE(value, precision=precision) if unit: result = lcg.concat(result, u'\xa0', unit) return result
def _format(self, context): g = context.generator() if self.spec.display(): values = self._row.display(self.id, export=localizable_export, single=False) else: values = [v.export() for v in self._value().value()] return lcg.concat([g.span(value) for value in values], separator=', ')
def _submenu(self, context): if not context.has_submenu: return None g = self._generator top = context.top_node() tree = lcg.FoldableTree(top, label=_("Local navigation: %s", top.title()), tooltip=_("Expand/collapse complete menu hierarchy")) content = tree.export(context) req = context.req() application = context.application title = application.menu_panel_title(req) if title: content = lcg.concat(g.h(title, 3, role='presentation', aria_hidden='true'), content) bottom_content = application.menu_panel_bottom_content(req) if bottom_content: content = lcg.concat(content, bottom_content.export(context)) return g.div(content, cls='menu-panel')
def _submenu(self, context): if not context.has_submenu: return None g = self._generator top = context.top_node() tree = lcg.FoldableTree(top, label=_("Local navigation: %s", top.title()), tooltip=_("Expand/collapse complete menu hierarchy")) content = tree.export(context) req = context.req() application = context.application title = application.menu_panel_title(req) if title: content = lcg.concat(g.h3(title, role='presentation', aria_hidden='true'), content) bottom_content = application.menu_panel_bottom_content(req) if bottom_content: content = lcg.concat(content, bottom_content.export(context)) return g.div(content, cls='menu-panel')
def _export_results(self, context, exercise, exercise_id): g = context.generator() return g.div((g.div(concat([g.label(label, exercise_id + '.' + name) + g.input(type='text', name=name, id=exercise_id + '.' + name, size=30, readonly=True) for name, label, help in self._INDICATORS], separator=g.br()), cls='display'), g.div([g.button(label, type=t, cls=name, title=hlp) for label, t, name, hlp in self._BUTTONS], cls='buttons')), cls='results')
def _links(self, context): g = self._generator links = [g.a(_("Main content"), href='#main-heading', accesskey="2")] if context.has_menu or context.has_submenu: links.append(g.a(_("Main navigation"), href='#main-navigation')) if context.has_menu and context.has_submenu: links.append(g.a(_("Local navigation"), href='#local-navigation')) if len(context.node().variants()) > 1: links.append(g.a(_("Language selection"), href='#language-selection-anchor')) if context.req().show_panels(): for panel in context.panels(): links.append(g.a(panel.accessible_title(), href='#panel-%s-anchor ' % panel.id())) return _("Jump in page") + ": " + lcg.concat(links, separator=' | ')
def _choice_control(self, context, exercise, exercise_id, task, choice): g = context.generator() result = self._choice_text(context, exercise, exercise_id, task, choice) if context.allow_interactivity(): i = task.choices().index(choice) task_name = self._task_id(exercise, exercise_id, task) choice_id = task_name + '-ch%d' % (i + 1) checked = self._checked(context, exercise, exercise_id, task, i) # Disable only the unchecked fields in the read-only mode. This makes the selection # unchangable in practice and has also the advantage that the checked fields can be # navigated, which is even better than using the `readonly' attribute (which doesn't # work in browsers anyway). disabled = self._readonly(context) and not checked ctrl = g.radio(task_name, id=choice_id, value=i, cls='answer-control', checked=checked, disabled=disabled) result = concat(ctrl, ' ', g.label(result, choice_id)) return result
def _choice_control(self, context, exercise, exercise_id, task, choice): g = context.generator() result = self._choice_text(context, exercise, exercise_id, task, choice) if context.allow_interactivity(): i = task.choices().index(choice) task_name = self._task_id(exercise, exercise_id, task) choice_id = task_name + '-ch%d' % (i + 1) checked = self._checked(context, exercise, exercise_id, task, i) # Disable only the unchecked fields in the read-only mode. This makes the selection # unchangable in practice and has also the advantage that the checked fields can be # navigated, which is even better than using the `readonly' attribute (which doesn't work # in browsers anyway). disabled = self._readonly(context) and not checked ctrl = g.radio(task_name, id=choice_id, value=i, cls='answer-control', checked=checked, disabled=disabled) result = concat(ctrl, ' ', g.label(result, choice_id)) return result
def _menu(self, context): g = self._generator items = [item for item in context.node().root().children() if not item.hidden()] if items: top = context.top_node() n = len(items) style = "width: %d%%" % (100 / n) last_style = "width: %d%%" % (100 - (100 / n * (n - 1))) first, last = items[0], items[-1] menu = [g.li(g.a(item.title(), href=self._uri_node(context, item), title=item.descr(), accesskey=(item is first and '1' or None), cls='navigation-link' + (item is top and ' current' or ''), ) + (item is top and self._hidden(' *') or ''), style=(item is last and last_style or style)) for item in items] title = g.a(_("Main navigation") + ':', name='main-navigation', accesskey="3") return lcg.concat(g.h(title, 3), g.div(g.ul(*menu), id='main-menu')) else: return None
def mknode(item): # Caution - make the same uri transformation as above to get same # results in all cases (such as for '/'). item_uri = "/" + item.id().strip("/") if item_uri == uri: # Note, the document title should not override the menu item title. # Only the main page heading is affected, but the ContentNode's # title matches the MenuItem's title. title = document.title() or item.title() if title and document.subtitle(): title = lcg.concat(title, " :: ", document.subtitle()) heading = lcg.TextContent(title) content = document.content() if isinstance(content, (list, tuple)): content = lcg.Container([c for c in content if c is not None]) variants = document.variants() if variants is None: variants = item.variants() globals_ = document.globals() else: variants = item.variants() heading = None content = None globals_ = None if variants is None: variants = all_variants node = lcg.ContentNode( item_uri, title=item.title(), heading=heading, descr=item.descr(), content=content, variants=[lcg.Variant(v) for v in variants], active=item.active(), foldable=item.foldable(), hidden=item.hidden() or lang not in variants, children=[mknode(i) for i in item.submenu()], resource_provider=resource_provider, globals=globals_, ) nodes[item_uri] = node return node
def _export_results(self, context, exercise, exercise_id): if not self._show_results(context): return None g = context.generator() points = self.eval(context.req()) # TODO: Display invalid value of entered added points within tutor's evaluation # (to let the tutor fix it). added = self.added_points(context.req()) max = self.max_points() def field(label, name, value, size=6, readonly=True, **kwargs): field_id = exercise_id + '-' + name return (g.label(label, field_id) + ' ' + g.input(type='text', name=id, value=value, id=field_id, size=size, readonly=readonly, cls=(readonly and 'display' or None), **kwargs)) if points < max and isinstance(self, FillInTestExporter): if added is None: total_points = points else: total_points = points + added # Javascript code to update the displayed total points dynamically. onchange = ("if (this.value=='') { points = 0; err='' } " "else if (isNaN(this.value)) { points = 0; err=' %(err_invalid)s' } " "else { points = parseInt(this.value); err='' }; " "if (points+%(points)d > %(max)d) { points=0; err=' %(err_exceed)s' } " "this.form.elements['%(exercise_id)s-total-points'].value = " "(points + %(points)d) + '/%(max)d'+err" % dict(points=points, max=max, exercise_id=exercise_id, err_invalid=_("Invalid value in added points!"), err_exceed=_("Max. points exceeded!"))) readonly = context.req().param('--allow-tutor-evaluation') is not True fields = [field(_("Automatic evaluation:"), 'points', points), field(_("Additional points by tutor:"), 'added-points', added or 0, readonly=readonly, onchange=(not readonly and onchange or None)), field(_("Total points:"), 'total-points', '%d/%d' % (total_points, max), size=40)] else: fields = [field(_("Total points:"), 'total-points', '%d/%d' % (points, max))] return g.div(concat(fields, separator=g.br()), cls='results')
def _make_field(self, context, exercise, exercise_id, task, text): g = context.generator() self._field_number += 1 field_id = self._task_id(exercise, exercise_id, task) + '-f%d' % self._field_number size = len(text) if size >= 2 and text == (size * '?'): # If the box contains just question marks, it means an unknown answer of one # word (two question marks) or one sencence (three or more question marks). size = 10 if size == 2 else 50 if not context.allow_interactivity(): field = g.span('_' * size, title=text, cls=self._field_cls(context, field_id, text)) else: field = concat( g.input(type='text', name=field_id, id=field_id, size=size, value=self._field_value(context, field_id), readonly=self._readonly(context), # Set the width through CSS. Otherwise the fields are too wide in FF. style='box-model: content-box; width: %dem;' % size, cls=self._field_cls(context, field_id, text)), [self._media_control(context, m, inline=True) for m in task.media()], self._field_result(context, field_id, text) ) return (context.localize(field), field_id)
def mknode(item): # Caution - make the same uri transformation as above to get same # results in all cases (such as for '/'). item_uri = '/' + item.id().strip('/') if item_uri == uri: # Note, the document title should not override the menu item title. # Only the main page heading is affected, but the ContentNode's # title matches the MenuItem's title. title = document.title() or item.title() if title and document.subtitle(): title = lcg.concat(title, ' :: ', document.subtitle()) heading = lcg.TextContent(title) content = document.content() if isinstance(content, (list, tuple)): content = lcg.Container([c for c in content if c is not None]) variants = document.variants() if variants is None: variants = item.variants() globals_ = document.globals() else: variants = item.variants() heading = None content = None globals_ = None if variants is None: variants = all_variants node = lcg.ContentNode(item_uri, title=item.title(), heading=heading, descr=item.descr(), content=content, variants=[lcg.Variant(v) for v in variants], active=item.active(), foldable=item.foldable(), hidden=item.hidden() or lang not in variants, children=[mknode(i) for i in item.submenu()], resource_provider=resource_provider, globals=globals_) nodes[item_uri] = node return node
def _make_field(self, context, exercise, exercise_id, task, text): g = context.generator() self._field_number += 1 field_id = self._task_id(exercise, exercise_id, task) + '-f%d' % self._field_number size = len(text) if size >= 2 and text == (size * '?'): # If the box contains just question marks, it means an unknown answer of one # word (two question marks) or one sencence (three or more question marks). size = 10 if size == 2 else 50 if not context.allow_interactivity(): field = g.span('_' * size, title=text, cls=self._field_cls(context, field_id, text)) else: field = concat( g.input(type='text', name=field_id, id=field_id, size=size, value=self._field_value(context, field_id), readonly=self._readonly(context), # Set the width through CSS. Otherwise the fields are too wide in FF. style='box-model: content-box; width: %dem;' % size, cls=self._field_cls(context, field_id, text)), [self._media_control(context, m) for m in task.media()], self._field_result(context, field_id, text) ) return (context.localize(field), field_id)
def _export_answers(self, context, exercise, exercise_id): g = context.generator() task_answers = [self._export_task_answer(context, exercise, exercise_id, task) for task in exercise.tasks()] return g.div(_("Answers: %s", lcg.concat(*task_answers, separator=', ')), cls='answers')
def _breadcrumbs(self, context): links = [lcg.link(n).export(context) for n in context.node().path()[1:]] # Translators: A label followed by location information in webpage navigation return _("You are here:") + ' ' + lcg.concat(links, separator=' / ')
def _links(self, context): g = self._generator links = [g.a(_("Main content"), href='#main-heading', accesskey="2")] for panel in context.panels(): links.append(g.a(panel.accessible_title(), href='#panel-%s-anchor ' % panel.id())) return _("Jump in page") + ": " + lcg.concat(links, separator=' | ')
def hidden(self, context): g = context.generator() return lcg.concat([ g.hidden(name=self.name(), value=value.export()) for value in self._value().value() ])