Commits

Anonymous committed 507b387

* more javascript client validation implementations (not finished tho)
* readme and changelog template based on Bill's jira issue
* javascript validation example has visitor example
* conversion errors now automatically have their original values displayed
* new feature in the valuestack: setPropertyOverrides() allows expressions to be
overriden (perfect for conversion error reporting stuff)

git-svn-id: http://svn.opensymphony.com/svn/webwork/trunk@379573baa09-0c28-0410-bef9-dab3c582ae83

Comments (0)

Files changed (17)

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- saved from url=(0067)http://jira.opensymphony.com/secure/attachment/10782/changelog.html -->
+<HTML><HEAD><TITLE>WebWork2 Changelog</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=windows-1252">
+<STYLE type=text/css>BODY {
+	FONT-SIZE: 100%
+}
+BODY {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+TD {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+TH {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+DIV {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+P {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+H1 {
+	FONT-SIZE: 14pt; BORDER-BOTTOM: #ccc 1px solid
+}
+TABLE {
+	BORDER-RIGHT: #ccc 1px solid; BORDER-TOP: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid; BORDER-BOTTOM: #ccc 1px solid
+}
+TH {
+	BACKGROUND-COLOR: #ddd; TEXT-ALIGN: left
+}
+UL {
+	PADDING-BOTTOM: 0.5em
+}
+UL UL {
+	PADDING-TOP: 0.5em
+}
+LI {
+	MARGIN-BOTTOM: 0.5em
+}
+.title {
+	FONT-WEIGHT: bold; FONT-SIZE: 11pt
+}
+.msg {
+	COLOR: #f00
+}
+.info {
+	FONT-SIZE: 0.9em; FONT-STYLE: italic
+}
+.issue {
+	FONT-WEIGHT: bold; FONT-SIZE: 0.9em; COLOR: #00f
+}
+.issue:visited {
+	COLOR: #600
+}
+.issue:hover {
+	COLOR: #f00
+}
+</STYLE>
+
+<META content="MSHTML 6.00.2737.800" name=GENERATOR></HEAD>
+<BODY>
+<H1>WebWork2 Changelog</H1><SPAN class=info>Version: <B>@version@</B> - Build 
+Date: <B>@builddate@</B> - <A 
+href="http://jira.opensymphony.com/secure/attachment/10782/README.html"><B>README</B></A> 
+- <A href="http://jira.opensymphony.com/"><B>Issue Tracker</B></A> </SPAN>
+<P>This is the WebWork2 changelog. This is a high-level list of changes and bug 
+fixes. A more exhaustive list of issues is maintained in the WebWork2 <A 
+href="http://jira.opensymphony.com/">issue tracker</A>. </P><BR>
+<P class=title><A 
+href="http://jira.opensymphony.com/secure/attachment/10782/">2.0.1</A> - Feb XX, 
+2004 </P>
+<UL>Bugfixes: 
+  <UL>
+    <LI><A class=issue 
+    href="http://jira.opensymphony.com/secure/attachment/10782/asdf0">WW-243</A> 
+    - Fixed class loader bug. 
+    <LI><A class=issue 
+    href="http://jira.opensymphony.com/secure/attachment/10782/asdf1">WW-666</A> 
+    - Fixed random System.exit(1) call. </LI></UL>New Features: 
+  <UL>
+    <LI><A class=issue 
+    href="http://jira.opensymphony.com/secure/attachment/10782/asdf2">WW-243</A>, 
+    <A class=issue 
+    href="http://jira.opensymphony.com/secure/attachment/10782/asdf3">WW-243</A> 
+    - Improved documentation 
+    <LI><A class=issue 
+    href="http://jira.opensymphony.com/secure/attachment/10782/asdf4">WW-661</A> 
+    - Added ability to brew cup of coffee. </LI></UL></UL>
+<P class=title><A 
+href="http://jira.opensymphony.com/secure/attachment/10782/">2.0.0</A> - Feb 9, 
+2004 </P>
+<UL>Initial release of WebWork2. </UL><BR><BR></BODY></HTML>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- saved from url=(0064)http://jira.opensymphony.com/secure/attachment/10766/README.html -->
+<HTML><HEAD><TITLE>WebWork2 README</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=windows-1252">
+<STYLE type=text/css>BODY {
+	FONT-SIZE: 100%
+}
+BODY {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+TD {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+TH {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+DIV {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+P {
+	FONT-SIZE: 9pt; FONT-FAMILY: verdana, arial, helvetica, sans-serif
+}
+H1 {
+	FONT-SIZE: 14pt; BORDER-BOTTOM: #ccc 1px solid
+}
+TABLE {
+	BORDER-RIGHT: #ccc 1px solid; BORDER-TOP: #ccc 1px solid; BORDER-LEFT: #ccc 1px solid; BORDER-BOTTOM: #ccc 1px solid
+}
+TH {
+	BACKGROUND-COLOR: #ddd; TEXT-ALIGN: left
+}
+UL {
+	PADDING-BOTTOM: 0.5em
+}
+LI {
+	MARGIN-BOTTOM: 0.5em
+}
+.title {
+	FONT-WEIGHT: bold; FONT-SIZE: 11pt
+}
+.msg {
+	COLOR: #f00
+}
+.info {
+	FONT-SIZE: 0.9em; FONT-STYLE: italic
+}
+</STYLE>
+
+<META content="MSHTML 6.00.2737.800" name=GENERATOR></HEAD>
+<BODY>
+<H1>WebWork2 README</H1><SPAN class=info>Version: <B>@version@</B> - Build Date: 
+<B>@builddate@</B> - <A 
+href="http://jira.opensymphony.com/secure/attachment/10766/changelog.html"><B>Changelog</B></A> 
+</SPAN>
+<P>Thank you for downloading WebWork2! The WebWork2 goal is to create the best 
+Model-2 MVC web application framework supporting advanced web application 
+development paradigms such as component based development and code reuse. </P>
+<P class=title>Key Features </P>
+<UL>
+  <LI>Built on <A href="http://wiki.opensymphony.com/space/XWork" 
+  target=_blank>XWork</A>, but customized to be specifically tailored for web 
+  application development 
+  <LI>Custom web-specific Xwork interceptors 
+  <LI>Flexible configuration extended from XWork with web-specific configuration 
+  parameters 
+  <LI>Multiple web-based views, including custom JSP taglibs, Velocity support 
+  with pre-built macros, XSLT views, and JasperReports </LI></UL>
+<P class=title>What's Included in this Release </P>
+<UL><PRE>/changelog.html          &lt;- Bug fixes, new features and improvements for this release.
+/README.html             &lt;- This file
+/webwork-2.0.jar         &lt;- Core classes and resources
+/webwork-example.war     &lt;- Demo application (see below)
+/webwork-migration.jar   &lt;- Migration classes for WebWork1 users
+/docs/                   &lt;- All documentation
+/lib/                    &lt;- All JARs - including optional JARs
+/src/                    &lt;- WebWork2 source code</PRE></UL>
+<P class=title>Documentation </P>
+<UL>
+  <LI><A 
+  href="http://jira.opensymphony.com/secure/attachment/10766/changelog.html">Changelog</A> 
+  for this release 
+  <LI><A 
+  href="http://jira.opensymphony.com/secure/attachment/10766/docs/quickstart.html">Quickstart 
+  Guide</A> 
+  <LI><A 
+  href="http://jira.opensymphony.com/secure/attachment/10766/docs/index.html">All 
+  documentation</A> for this release 
+  <LI><A href="http://wiki.opensymphony.com/space/WebWork2">WebWork2 Wiki</A> 
+  (all the latest documentation) </LI></UL>
+<P class=title>Demos </P>
+<UL>
+  <LI>To run the webwork demo application you will need to install the 
+  <TT>webwork-example.war</TT> file included with this distribution to your 
+  Servlet container. Your Servlet container must support the Servlet 2.3 spec 
+  and JSP 1.1 spec at a minimum. </LI></UL>
+<P class=title>Mailing Lists </P>
+<UL>
+  <LI><A 
+  href="http://lists.sourceforge.net/mailman/listinfo/opensymphony-webwork">XWork 
+  / WebWork2</A> mailing list - for general support, help and development of 
+  WebWork2. 
+  <LI><A 
+  href="https://webwork.dev.java.net/servlets/SummarizeList?listName=cvs">WebWork 
+  CVS list</A> (for developers) 
+  <LI><A 
+  href="https://xwork.dev.java.net/servlets/SummarizeList?listName=cvs">XWork 
+  CVS list</A> (for developers) </LI></UL>
+<P class=title>Issue Tracker </P>
+<UL>
+  <LI><A 
+  href="http://jira.opensymphony.com/secure/BrowseProject.jspa?id=10030">Online 
+  Issue Tracker</A> - Please submit bug reports or RFE's here. 
+</LI></UL><BR><BR></BODY></HTML>

src/example/com/opensymphony/webwork/example/JavascriptValidationAction-javascriptValidation-validation.xml

 <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
 <validators>
-    <field name="test">
+    <field name="requiredString">
         <field-validator type="requiredstring">
             <message>You must enter a string.</message>
         </field-validator>
     </field>
+
+    <field name="intRange">
+        <field-validator type="int">
+            <param name="min">1</param>
+            <param name="max">10</param>
+            <message>You must select a number between 1 and 10</message>
+        </field-validator>
+    </field>
+
+    <field name="email">
+        <field-validator type="email">
+            <message>You must enter a valid email address.</message>
+        </field-validator>
+    </field>
+
+    <field name="url">
+        <field-validator type="url">
+            <message>You must enter a valid URL.</message>            
+        </field-validator>
+    </field>
+
+    <field name="date">
+        <field-validator type="date">
+            <param name="min">2/12/1982</param>
+            <param name="max">2/12/2004</param>
+            <message>You must select a date between 2/12/1982 and 2/12/2004</message>
+        </field-validator>
+    </field>
+
+    <field name="bean">
+        <field-validator type="visitor">
+            <message>bean: </message>
+        </field-validator>
+    </field>
+
 </validators>

src/example/com/opensymphony/webwork/example/JavascriptValidationAction.java

 
 import webwork.action.ActionSupport;
 
+import java.util.Date;
+
 public class JavascriptValidationAction extends ActionSupport {
-    String test;
+
+    String requiredString;
+    int intRange;
+    String email;
+    String url;
+    Date date;
+    ValidatedBean bean = new ValidatedBean();
 
     public String execute() throws Exception {
-        System.out.println("You entered: " + test);
         return SUCCESS;
     }
 
         return INPUT;
     }
 
-    public String getTest() {
-        return test;
+
+    public String getRequiredString() {
+        return requiredString;
+    }
+
+    public void setRequiredString(String requiredString) {
+        this.requiredString = requiredString;
+    }
+
+    public int getIntRange() {
+        return intRange;
+    }
+
+    public void setIntRange(int intRange) {
+        this.intRange = intRange;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public ValidatedBean getBean() {
+        return bean;
     }
 
-    public void setTest(String test) {
-        this.test = test;
+    public void setBean(ValidatedBean bean) {
+        this.bean = bean;
     }
 }

src/example/validators.xml

 <validators>
     <validator name="required" class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/>
     <validator name="requiredstring" class="com.opensymphony.webwork.validators.JavaScriptRequiredStringValidator"/>
-    <validator name="int" class="com.opensymphony.xwork.validator.validators.IntRangeFieldValidator"/>
-    <validator name="date" class="com.opensymphony.xwork.validator.validators.DateRangeFieldValidator"/>
+    <validator name="int" class="com.opensymphony.webwork.validators.JavaScriptIntRangeFieldValidator"/>
+    <validator name="date" class="com.opensymphony.webwork.validators.JavaScriptDateRangeFieldValidator"/>
     <validator name="expression" class="com.opensymphony.xwork.validator.validators.ExpressionValidator"/>
     <validator name="fieldexpression" class="com.opensymphony.xwork.validator.validators.FieldExpressionValidator"/>
-    <validator name="email" class="com.opensymphony.xwork.validator.validators.EmailValidator"/>
-    <validator name="url" class="com.opensymphony.xwork.validator.validators.URLValidator"/>
-    <validator name="visitor" class="com.opensymphony.xwork.validator.validators.VisitorFieldValidator"/>
+    <validator name="email" class="com.opensymphony.webwork.validators.JavaScriptEmailValidator"/>
+    <validator name="url" class="com.opensymphony.webwork.validators.JavaScriptURLValidator"/>
+    <validator name="visitor" class="com.opensymphony.webwork.validators.JavaScriptVisitorFieldValidator"/>
     <validator name="conversion" class="com.opensymphony.xwork.validator.validators.ConversionErrorFieldValidator"/>
 </validators>

src/java/com/opensymphony/webwork/interceptor/WebWorkConversionErrorInterceptor.java

 package com.opensymphony.webwork.interceptor;
 
 import com.opensymphony.xwork.interceptor.ConversionErrorInterceptor;
+import com.opensymphony.xwork.util.XWorkConverter;
+import com.opensymphony.xwork.util.OgnlValueStack;
+import com.opensymphony.xwork.ActionInvocation;
 
 
 /**
  */
 public class WebWorkConversionErrorInterceptor extends ConversionErrorInterceptor {
 
+    protected Object getOverrideExpr(ActionInvocation invocation, Object value) {
+        OgnlValueStack stack = invocation.getStack();
+        try {
+            stack.push(value);
+            return "'" + stack.findValue("top", String.class) + "'";
+        } finally {
+            stack.pop();
+        }
+    }
+
+
     /**
      * Returns <tt>false</tt> if the value is null, "", or {""} (array of size 1 with
      * a blank element). Returns <tt>true</tt> otherwise.

src/java/com/opensymphony/webwork/validators/JavaScriptDateRangeFieldValidator.java

+package com.opensymphony.webwork.validators;
+
+import com.opensymphony.xwork.validator.validators.DateRangeFieldValidator;
+
+import java.util.Map;
+
+public class JavaScriptDateRangeFieldValidator extends DateRangeFieldValidator implements ScriptValidationAware {
+    public String validationScript(Map parameters) {
+        return "";
+    }
+}

src/java/com/opensymphony/webwork/validators/JavaScriptEmailValidator.java

+package com.opensymphony.webwork.validators;
+
+import com.opensymphony.xwork.validator.validators.EmailValidator;
+
+import java.util.Map;
+
+public class JavaScriptEmailValidator extends EmailValidator implements ScriptValidationAware {
+    public String validationScript(Map parameters) {
+        String field = (String) parameters.get("name");
+        StringBuffer js = new StringBuffer();
+
+        js.append("value = form.elements['" + field + "'].value;\n");
+        js.append("if (value == \"\") {\n");
+        js.append("\talert('" + getMessage(null) + "');\n");
+        js.append("\treturn '" + field + "';\n");
+        js.append("}\n");
+        js.append("\n");
+
+        return js.toString();
+    }
+}

src/java/com/opensymphony/webwork/validators/JavaScriptIntRangeFieldValidator.java

+package com.opensymphony.webwork.validators;
+
+import com.opensymphony.xwork.validator.validators.IntRangeFieldValidator;
+
+import java.util.Map;
+
+public class JavaScriptIntRangeFieldValidator extends IntRangeFieldValidator implements ScriptValidationAware {
+    public String validationScript(Map parameters) {
+        String field = (String) parameters.get("name");
+        StringBuffer js = new StringBuffer();
+
+        js.append("value = form.elements['" + field + "'].value;\n");
+        js.append("if (value < " + getMin() + " || value > " + getMax() + ") {\n");
+        js.append("\talert('" + getMessage(null) + "');\n");
+        js.append("\treturn '" + field + "';\n");
+        js.append("}\n");
+        js.append("\n");
+
+        return js.toString();
+    }
+}

src/java/com/opensymphony/webwork/validators/JavaScriptRequiredStringValidator.java

         js.append("value = form.elements['" + field + "'].value;\n");
         js.append("if (value == \"\") {\n");
         js.append("\talert('" + getMessage(null) + "');\n");
-        js.append("\treturn false;\n");
+        js.append("\treturn '" + field + "';\n");
         js.append("}\n");
         js.append("\n");
 

src/java/com/opensymphony/webwork/validators/JavaScriptURLValidator.java

+package com.opensymphony.webwork.validators;
+
+import com.opensymphony.xwork.validator.validators.URLValidator;
+
+import java.util.Map;
+
+public class JavaScriptURLValidator extends URLValidator implements ScriptValidationAware {
+    public String validationScript(Map parameters) {
+        return "";
+    }
+}

src/java/com/opensymphony/webwork/validators/JavaScriptVisitorFieldValidator.java

+package com.opensymphony.webwork.validators;
+
+import com.opensymphony.xwork.validator.validators.VisitorFieldValidator;
+
+import java.util.Map;
+
+public class JavaScriptVisitorFieldValidator extends VisitorFieldValidator implements ScriptValidationAware {
+    public String validationScript(Map parameters) {
+        return "";
+    }
+}

src/java/com/opensymphony/webwork/validators/ScriptValidationAware.java

 package com.opensymphony.webwork.validators;
 
+import com.opensymphony.xwork.validator.FieldValidator;
+
 import java.util.Map;
 
-public interface ScriptValidationAware {
+public interface ScriptValidationAware extends FieldValidator {
     public String validationScript(Map parameters);
 }

src/java/com/opensymphony/webwork/views/jsp/ui/AbstractUITag.java

 import com.opensymphony.webwork.config.Configuration;
 import com.opensymphony.webwork.views.jsp.ParameterizedTagSupport;
 import com.opensymphony.webwork.views.velocity.VelocityManager;
+import com.opensymphony.webwork.validators.ScriptValidationAware;
 import com.opensymphony.xwork.util.OgnlValueStack;
 import com.opensymphony.xwork.validator.ActionValidatorManager;
 import com.opensymphony.xwork.validator.FieldValidator;
             List validators = ActionValidatorManager.getValidators(tag.getActionClass(), tag.getActionName());
             for (Iterator iterator = validators.iterator(); iterator.hasNext();) {
                 Validator validator = (Validator) iterator.next();
-                if (validator instanceof FieldValidator) {
-                    FieldValidator fieldValidator = (FieldValidator) validator;
+                if (validator instanceof ScriptValidationAware) {
+                    ScriptValidationAware fieldValidator = (ScriptValidationAware) validator;
                     if (fieldValidator.getFieldName().equals(name)) {
                         tag.registerValidator(name, fieldValidator, new HashMap(getParameters()));
                     }

src/java/com/opensymphony/webwork/views/jsp/ui/FormTag.java

 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
     String enctypeAttr;
     String methodAttr;
     String validateAttr;
-    Map fieldValidators;
-    Map fieldParameters;
+    List fieldValidators;
+    List fieldParameters;
     Class actionClass;
     String actionName;
 
 
         if (fieldValidators != null) {
             StringBuffer js = new StringBuffer();
-            js.append("form = document.forms['" + getParameters().get("name") + "'];\n");
-            for (Iterator iterator = fieldValidators.entrySet().iterator(); iterator.hasNext();) {
-                Map.Entry entry = (Map.Entry) iterator.next();
-                if (entry.getValue() instanceof ScriptValidationAware) {
-                    ScriptValidationAware jsa = (ScriptValidationAware) entry.getValue();
-                    Map params = (Map) fieldParameters.get(entry.getKey());
-                    js.append(jsa.validationScript(params));
-                    js.append('\n');
-                }
+            // loop backwards so that the first elements are validated first
+            for (int i = 0; i < fieldValidators.size(); i++) {
+                ScriptValidationAware sva = (ScriptValidationAware) fieldValidators.get(i);
+                Map params = (Map) fieldParameters.get(i);
+                js.append(sva.validationScript(params));
+                js.append('\n');
             }
-
             addParameter("javascriptValidation", js.toString());
         }
     }
         return TEMPLATE;
     }
 
-    public void registerValidator(Object name, FieldValidator fieldValidator, Map params) {
+    public void registerValidator(Object name, ScriptValidationAware sva, Map params) {
         if (fieldValidators == null) {
-            fieldValidators = new HashMap();
-        }
-
-        if (fieldParameters == null) {
-            fieldParameters = new HashMap();
+            fieldValidators = new ArrayList();
+            fieldParameters = new ArrayList();
         }
 
-        fieldValidators.put(name, fieldValidator);
-        fieldParameters.put(name, params);
-    }
-
-    public Map getFieldValidators() {
-        return fieldValidators;
-    }
-
-    public Map getFieldParameters() {
-        return fieldParameters;
+        fieldValidators.add(sva);
+        fieldParameters.add(params);
     }
 
     public Class getActionClass() {

src/java/template/xhtml/form-close.vm

 #if ($parameters.validate)
     <script>
     function ${parameters.name}_validate() {
+        var form = document.forms['${parameters.name}'];
+        var focus = ${parameters.name}_validate_actual();
+        if (focus != null) {
+            form.elements[focus].focus();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    function ${parameters.name}_validate_actual() {
+        var form = document.forms['${parameters.name}'];
         $parameters.javascriptValidation
-        return true;
+        return null;
     }
     </script>
 #end

src/webapp/javascript-input.jsp

     
     <body>
         <ww:form name="'test'" action="'javascriptValidation'" validate="true" >
-            <ww:textfield label="'Can't be empty'" name="'test'" required="true"/>
+            <ww:textfield label="'Required String'" name="'requiredString'" required="true"/>
+            <ww:textfield label="'Some Int'" name="'intRange'" required="true"/>
+            <ww:textfield label="'Email'" name="'email'" required="true"/>
+            <ww:textfield label="'URL'" name="'url'" required="true"/>
+            <ww:textfield label="'Date'" name="'date'" required="true"/>
+            <tr><td colspan="2"><hr/></td></tr>
+            <ww:textfield label="'Bean Text'" name="'bean.text'" required="true"/>
+            <ww:textfield label="'Bean Date'" name="'bean.date'" required="true"/>
+            <ww:textfield label="'Bean Number'" name="'bean.number'" required="true"/>
             <ww:submit value="'Submit'"/>
         </ww:form>
     </body>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.