Merge lp:~methanal-developers/methanal/808474-liveform-validation-error-list into lp:methanal

Proposed by Jonathan Jacobs
Status: Merged
Approved by: Tristan Seligmann
Approved revision: 181
Merged at revision: 182
Proposed branch: lp:~methanal-developers/methanal/808474-liveform-validation-error-list
Merge into: lp:methanal
Diff against target: 278 lines (+147/-9)
4 files modified
methanal/js/Methanal/Tests/TestUtil.js (+23/-0)
methanal/js/Methanal/Util.js (+31/-5)
methanal/js/Methanal/View.js (+78/-3)
methanal/view.py (+15/-1)
To merge this branch: bzr merge lp:~methanal-developers/methanal/808474-liveform-validation-error-list
Reviewer Review Type Date Requested Status
Tristan Seligmann Approve
Review via email: mp+67601@code.launchpad.net
To post a comment you must log in.
181. By Jonathan Jacobs

Docstring.

Revision history for this message
Tristan Seligmann (mithrandi) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'methanal/js/Methanal/Tests/TestUtil.js'
--- methanal/js/Methanal/Tests/TestUtil.js 2011-03-08 08:47:01 +0000
+++ methanal/js/Methanal/Tests/TestUtil.js 2011-07-12 10:29:32 +0000
@@ -517,6 +517,29 @@
517 self.assertIdentical(517 self.assertIdentical(
518 Methanal.Util.unapply(f)(1, 2, 3),518 Methanal.Util.unapply(f)(1, 2, 3),
519 6);519 6);
520 },
521
522
523 /**
524 * Pluralise a word.
525 */
526 function test_plural(self) {
527 var plural = Methanal.Util.plural;
528 self.assertIdentical(
529 plural(1, 'hammer'),
530 'hammer');
531 self.assertIdentical(
532 plural(0, 'hammer'),
533 'hammers');
534 self.assertIdentical(
535 plural(2, 'hammer'),
536 'hammers');
537 self.assertIdentical(
538 plural(-1, 'hammer'),
539 'hammers');
540 self.assertIdentical(
541 plural(2, 'fix', 'fixes'),
542 'fixes');
520 });543 });
521544
522545
523546
=== modified file 'methanal/js/Methanal/Util.js'
--- methanal/js/Methanal/Util.js 2011-07-04 14:15:27 +0000
+++ methanal/js/Methanal/Util.js 2011-07-12 10:29:32 +0000
@@ -1373,7 +1373,8 @@
1373 var orientationClass = POINTER_ORIENTATIONS[self.orientation] || '';1373 var orientationClass = POINTER_ORIENTATIONS[self.orientation] || '';
1374 self.node = D('span', {'class': self.extraClassName}, [1374 self.node = D('span', {'class': self.extraClassName}, [
1375 D('div', {'class': 'hover-tooltip ' + orientationClass}, [1375 D('div', {'class': 'hover-tooltip ' + orientationClass}, [
1376 text, D('div', {'class': 'hover-tooltip-arrow'})])]);1376 text, D('div', {'class': 'hover-tooltip-arrow'})]),
1377 D('div', {'class': 'terminator'})]);
1377 if (self._hidden) {1378 if (self._hidden) {
1378 self.hide();1379 self.hide();
1379 }1380 }
@@ -1383,19 +1384,44 @@
13831384
13841385
1385/**1386/**
1386 * Tooltip "pointer" (the tail end of the tooltip) orientations::1387 * Tooltip "pointer" (the tail end of the tooltip) orientations:
1387 *1388 *
1388 * none:1389 * - none:
1389 * Tooltip has no tail.1390 * Tooltip has no tail.
1390 *1391 *
1391 * left:1392 * - left:
1392 * Tail comes from the left edge.1393 * Tail comes from the left edge.
1393 *1394 *
1394 * bottom:1395 * - bottom:
1395 * Tail comes from the bottom edge.1396 * Tail comes from the bottom edge.
1397 *
1398 * - top:
1399 * Tail comes from the top edge.
1396 */1400 */
1397Methanal.Util.Tooltip.POINTER_ORIENTATIONS = {1401Methanal.Util.Tooltip.POINTER_ORIENTATIONS = {
1398 'none': '',1402 'none': '',
1399 'left': 'hover-tooltip-left',1403 'left': 'hover-tooltip-left',
1400 'bottom': 'hover-tooltip-bottom',1404 'bottom': 'hover-tooltip-bottom',
1401 'top': 'hover-tooltip-top'};1405 'top': 'hover-tooltip-top'};
1406
1407
1408
1409/**
1410 * Pluralise a word.
1411 *
1412 * @type n: C{Number}
1413 * @param n: Count.
1414 *
1415 * @type word: C{String}
1416 * @param word: Word to pluralise.
1417 *
1418 * @type pluralForm: C{String}
1419 * @param pluralForm: Plural form of L{word}, defaults to C{word + 's'}.
1420 *
1421 * @rtype: C{String}
1422 * @return: Plural form of C{word} it C{n} indicates it should be a plural.
1423 */
1424Methanal.Util.plural = function plural(n, word, pluralForm/*=undefined*/) {
1425 pluralForm = pluralForm || word + 's';
1426 return n == 1 ? word : pluralForm;
1427};
14021428
=== modified file 'methanal/js/Methanal/View.js'
--- methanal/js/Methanal/View.js 2011-07-11 17:14:43 +0000
+++ methanal/js/Methanal/View.js 2011-07-12 10:29:32 +0000
@@ -443,14 +443,19 @@
443 return;443 return;
444 }444 }
445445
446 var invalidControls = [];
446 for (var controlName in self.controls) {447 for (var controlName in self.controls) {
447 var control = self.getControl(controlName);448 var control = self.getControl(controlName);
448 if (control.active && control.error) {449 if (control.active && control.error) {
449 self.setInvalid();450 invalidControls.push(control);
450 return;
451 }451 }
452 }452 }
453453
454 if (invalidControls.length) {
455 self.setInvalid(invalidControls);
456 return;
457 }
458
454 for (var name in self.subforms) {459 for (var name in self.subforms) {
455 if (!self.subforms[name].valid) {460 if (!self.subforms[name].valid) {
456 self.setInvalid();461 self.setInvalid();
@@ -958,6 +963,10 @@
958 * @ivar hideModificationIndicator: Hide the modification indicator for this963 * @ivar hideModificationIndicator: Hide the modification indicator for this
959 * form? Defaults to C{false}.964 * form? Defaults to C{false}.
960 *965 *
966 * @type hideValidationErrorIndicator: C{boolean}
967 * @ivar hideValidationErrorIndicator: Hide the validation error indicator for
968 * this form? Defaults to C{false}.
969 *
961 * @type controlNames: C{object} of C{String}970 * @type controlNames: C{object} of C{String}
962 * @ivar controlNames: Names of form inputs as a mapping971 * @ivar controlNames: Names of form inputs as a mapping
963 *972 *
@@ -986,6 +995,7 @@
986 }995 }
987 self.viewOnly = args.viewOnly;996 self.viewOnly = args.viewOnly;
988 self.hideModificationIndicator = args.hideModificationIndicator;997 self.hideModificationIndicator = args.hideModificationIndicator;
998 self.hideValidationErrorIndicator = args.hideValidationErrorIndicator;
989 if (!(controlNames instanceof Array)) {999 if (!(controlNames instanceof Array)) {
990 throw new Error('"controlNames" must be an Array of control names');1000 throw new Error('"controlNames" must be an Array of control names');
991 }1001 }
@@ -999,6 +1009,9 @@
9991009
1000 function nodeInserted(self) {1010 function nodeInserted(self) {
1001 self._formErrorNode = self.nodeById('form-error');1011 self._formErrorNode = self.nodeById('form-error');
1012 self._validationErrorTooltip = Methanal.Util.Tooltip(
1013 self.node, null, 'top', 'error-tooltip submission-error-tooltip ' +
1014 'form-validation-error-tooltip');
1002 },1015 },
10031016
10041017
@@ -1225,15 +1238,58 @@
1225 function setValid(self) {1238 function setValid(self) {
1226 self.valid = true;1239 self.valid = true;
1227 self.actions.enable();1240 self.actions.enable();
1241 self._validationErrorTooltip.hide();
1242 },
1243
1244
1245 /**
1246 * Create and display the form validation error tooltip if necessary.
1247 */
1248 function _showFormValidationErrorTooltip(self, invalidControls) {
1249 if (self.hideValidationErrorIndicator) {
1250 return;
1251 }
1252
1253 function focusControl(control) {
1254 return function () {
1255 control.focus(true);
1256 return false;
1257 }
1258 }
1259
1260 var D = Methanal.Util.DOMBuilder(self.node.ownerDocument);
1261 var errors = [];
1262 for (var i = 0; i < invalidControls.length; ++i) {
1263 var control = invalidControls[i];
1264 var label = control.label || control.name;
1265 var a = D('a', {'href': '#', 'title': control.error},
1266 [label.replace(/\s/g, '\xa0')]);
1267 a.onclick = focusControl(control);
1268 errors.push(D('span', {}, [a, ' ']));
1269 }
1270
1271 var numErrors = errors.length;
1272 if (numErrors) {
1273 var errorText = D('span', {}, [
1274 D('h2', {}, [
1275 errors.length.toString() + ' validation ' +
1276 Methanal.Util.plural(numErrors, 'error')]),
1277 D('p', {}, errors)]);
1278 self._validationErrorTooltip.setText(errorText);
1279 self._validationErrorTooltip.show();
1280 }
1228 },1281 },
12291282
12301283
1231 /**1284 /**
1232 * Disable form submission.1285 * Disable form submission.
1233 */1286 */
1234 function setInvalid(self) {1287 function setInvalid(self, invalidControls) {
1235 self.valid = false;1288 self.valid = false;
1236 self.actions.disable();1289 self.actions.disable();
1290 if (invalidControls !== undefined && invalidControls.length) {
1291 self._showFormValidationErrorTooltip(invalidControls);
1292 }
1237 });1293 });
12381294
12391295
@@ -1539,6 +1595,25 @@
15391595
15401596
1541 /**1597 /**
1598 * Give keyboard focus to the form input.
1599 */
1600 function focus(self, scrollIntoView/*=true*/) {
1601 if (!self.inputNode) {
1602 return;
1603 }
1604
1605 if (self.inputNode.focus !== undefined) {
1606 self.inputNode.focus();
1607 }
1608 if (scrollIntoView === undefined || scrollIntoView) {
1609 if (self.inputNode.scrollIntoView) {
1610 self.inputNode.scrollIntoView(true);
1611 }
1612 }
1613 },
1614
1615
1616 /**
1542 * Has this input finished loading?1617 * Has this input finished loading?
1543 */1618 */
1544 function isLoaded(self) {1619 function isLoaded(self) {
15451620
=== modified file 'methanal/view.py'
--- methanal/view.py 2011-06-12 22:16:10 +0000
+++ methanal/view.py 2011-07-12 10:29:32 +0000
@@ -240,6 +240,14 @@
240 @ivar viewOnly: Flag indicating whether model values are written back when240 @ivar viewOnly: Flag indicating whether model values are written back when
241 invoked.241 invoked.
242242
243 @type hideModificationIndicator: C{bool}
244 @ivar hideModificationIndicator: Hide the modification indicator for this
245 form? Defaults to C{False}.
246
247 @type hideValidationErrorIndicator: C{bool}
248 @ivar hideValidationErrorIndicator: Hide the validation error indicator for
249 this form? Defaults to C{False}.
250
243 @type actions: L{ActionContainer}251 @type actions: L{ActionContainer}
244252
245 @type doc: C{unicode}253 @type doc: C{unicode}
@@ -262,6 +270,9 @@
262 self.actions = actions270 self.actions = actions
263 self.doc = doc271 self.doc = doc
264272
273 self.hideModificationIndicator = False
274 self.hideValidationErrorIndicator = False
275
265276
266 def getInitialArguments(self):277 def getInitialArguments(self):
267 args = super(LiveForm, self).getInitialArguments()278 args = super(LiveForm, self).getInitialArguments()
@@ -269,7 +280,10 @@
269280
270281
271 def getArgs(self):282 def getArgs(self):
272 return {u'viewOnly': self.viewOnly}283 return {
284 u'viewOnly': self.viewOnly,
285 u'hideModificationIndicator': self.hideModificationIndicator,
286 u'hideValidationErrorIndicator': self.hideValidationErrorIndicator}
273287
274288
275 @renderer289 @renderer

Subscribers

People subscribed via source and target branches

to all changes: