resty-generators 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/generators/resty/base.rb +33 -5
- data/lib/generators/resty/controller/controller_generator.rb +2 -2
- data/lib/generators/resty/model/model_generator.rb +1 -1
- data/lib/generators/resty/scaffold/scaffold_generator.rb +76 -4
- data/lib/generators/resty/setup/setup_generator.rb +141 -4
- data/lib/generators/resty/setup/templates/ActivityFactory.java +12 -0
- data/lib/generators/resty/setup/templates/ActivityPlace.java +25 -0
- data/lib/generators/resty/setup/templates/ActivityPlaceActivityMapper.java +30 -0
- data/lib/generators/resty/setup/templates/BreadCrumbsPanel.java +80 -0
- data/lib/generators/resty/setup/templates/EntryPoint.java +75 -4
- data/lib/generators/resty/setup/templates/GinModule.java +40 -0
- data/lib/generators/resty/setup/templates/LoginActivity.java +59 -0
- data/lib/generators/resty/setup/templates/LoginPlace.java +20 -0
- data/lib/generators/resty/setup/templates/LoginView.ui.xml +18 -0
- data/lib/generators/resty/setup/templates/LoginViewImpl.java +21 -0
- data/lib/generators/resty/setup/templates/Mavenfile +7 -4
- data/lib/generators/resty/setup/templates/PlaceHistoryMapper.java +8 -0
- data/lib/generators/resty/setup/templates/RestfulPlace.java +24 -0
- data/lib/generators/resty/setup/templates/SessionActivityPlaceActivityMapper.java +71 -0
- data/lib/generators/resty/setup/templates/SessionRestService.java +23 -0
- data/lib/generators/resty/setup/templates/User.java +8 -0
- data/lib/generators/resty/setup/templates/authentication.rb +3 -0
- data/lib/generators/resty/setup/templates/empty.css +17 -0
- data/lib/generators/resty/setup/templates/gitignore +3 -0
- data/lib/generators/resty/setup/templates/group.rb +14 -0
- data/lib/generators/resty/setup/templates/gwt.css +17 -0
- data/lib/generators/resty/setup/templates/module.gwt.xml +9 -2
- data/lib/generators/resty/setup/templates/page.html +1 -1
- data/lib/generators/resty/setup/templates/session.rb +45 -0
- data/lib/generators/resty/setup/templates/sessions_controller.rb +29 -0
- data/lib/generators/resty/setup/templates/user.rb +28 -0
- data/lib/generators/resty/setup/templates/web.xml +50 -0
- data/lib/generators/resty/templates/Activity.java +140 -0
- data/lib/generators/resty/templates/ColumnDefinitionsImpl.java +24 -0
- data/lib/generators/resty/templates/Model.java +13 -7
- data/lib/generators/resty/templates/Place.java +27 -0
- data/lib/generators/resty/templates/PlaceTokenizer.java +25 -0
- data/lib/generators/resty/templates/{Controller.java → RestService.java} +16 -12
- data/lib/generators/resty/templates/View.java +35 -0
- data/lib/generators/resty/templates/View.ui.xml +47 -0
- data/lib/generators/resty/templates/ViewImpl.java +196 -0
- data/lib/resty-generators.rb +1 -0
- data/lib/resty/child_path.rb +17 -4
- data/lib/resty/resty_railtie.rb +4 -5
- metadata +70 -60
@@ -1,19 +1,90 @@
|
|
1
1
|
package <%= base_package %>;
|
2
2
|
|
3
|
+
import <%= managed_package %>.<%= application_name %>PlaceHistoryMapper;
|
4
|
+
import <%= managed_package %>.<%= application_name %>Module;
|
5
|
+
|
6
|
+
import com.google.gwt.activity.shared.ActivityManager;
|
3
7
|
import com.google.gwt.core.client.EntryPoint;
|
4
|
-
import com.google.gwt.
|
8
|
+
import com.google.gwt.core.client.GWT;
|
9
|
+
import com.google.gwt.event.shared.EventBus;
|
10
|
+
import com.google.gwt.inject.client.GinModules;
|
11
|
+
import com.google.gwt.inject.client.Ginjector;
|
12
|
+
import com.google.gwt.place.shared.Place;
|
13
|
+
import com.google.gwt.place.shared.PlaceController;
|
14
|
+
import com.google.gwt.place.shared.PlaceHistoryHandler;
|
15
|
+
import com.google.gwt.user.client.ui.Panel;
|
5
16
|
import com.google.gwt.user.client.ui.RootPanel;
|
17
|
+
import com.google.inject.Inject;
|
18
|
+
|
19
|
+
import <%= gwt_rails_package %>.Application;
|
20
|
+
import <%= gwt_rails_package %>.Notice;
|
21
|
+
import <%= gwt_rails_package %>.DefaultDispatcherSingleton;
|
22
|
+
|
23
|
+
import org.fusesource.restygwt.client.Defaults;
|
6
24
|
|
7
25
|
/**
|
8
26
|
* Entry point classes define <code>onModuleLoad()</code>.
|
9
27
|
*/
|
10
|
-
public class <%= application_name %> implements EntryPoint {
|
28
|
+
public class <%= application_name %>EntryPoint implements EntryPoint {
|
29
|
+
|
30
|
+
@GinModules(<%= application_name %>Module.class)
|
31
|
+
static public interface <%= application_name %>Ginjector extends Ginjector {
|
32
|
+
PlaceController getPlaceController();
|
33
|
+
EventBus getEventBus();
|
34
|
+
Application getApplication();
|
35
|
+
}
|
36
|
+
|
37
|
+
static public class <%= application_name %>Application extends Application {
|
38
|
+
private final Notice notice;
|
39
|
+
<% if options[:session] -%>
|
40
|
+
private final BreadCrumbsPanel breadCrumbs;
|
41
|
+
<% end -%>
|
42
|
+
private RootPanel root;
|
43
|
+
|
44
|
+
@Inject
|
45
|
+
<%= application_name %>Application(final Notice notice,
|
46
|
+
<% if options[:session] -%>
|
47
|
+
final BreadCrumbsPanel breadCrumbs,
|
48
|
+
<% end -%>
|
49
|
+
final ActivityManager activityManager){
|
50
|
+
super(activityManager);
|
51
|
+
this.notice = notice;
|
52
|
+
<% if options[:session] -%>
|
53
|
+
this.breadCrumbs = breadCrumbs;
|
54
|
+
<% end -%>
|
55
|
+
}
|
56
|
+
|
57
|
+
protected Panel getApplicationPanel(){
|
58
|
+
if (this.root == null) {
|
59
|
+
this.root = RootPanel.get();
|
60
|
+
this.root.add(notice);
|
61
|
+
<% if options[:session] -%>
|
62
|
+
this.root.add(breadCrumbs);
|
63
|
+
<% end -%>
|
64
|
+
}
|
65
|
+
return this.root;
|
66
|
+
}
|
67
|
+
}
|
11
68
|
|
12
69
|
/**
|
13
70
|
* This is the entry point method.
|
14
71
|
*/
|
15
72
|
public void onModuleLoad() {
|
16
|
-
|
17
|
-
|
73
|
+
Defaults.setServiceRoot(GWT.getModuleBaseURL().replaceFirst("[a-z]+/$", ""));
|
74
|
+
Defaults.setDispatcher(DefaultDispatcherSingleton.INSTANCE);
|
75
|
+
GWT.log("base url for restservices: " + Defaults.getServiceRoot());
|
76
|
+
|
77
|
+
final <%= application_name %>Ginjector injector = GWT.create(<%= application_name %>Ginjector.class);
|
78
|
+
|
79
|
+
injector.getApplication().run();
|
18
80
|
|
81
|
+
// Start PlaceHistoryHandler with our PlaceHistoryMapper
|
82
|
+
<%= application_name %>PlaceHistoryMapper historyMapper = GWT.create(<%= application_name %>PlaceHistoryMapper.class);
|
83
|
+
|
84
|
+
PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
|
85
|
+
historyHandler.register(injector.getPlaceController(), injector.getEventBus(), Place.NOWHERE);
|
86
|
+
|
87
|
+
// Goes to the place represented on URL else default place
|
88
|
+
historyHandler.handleCurrentHistory();
|
89
|
+
}
|
19
90
|
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
package <%= managed_package %>;
|
2
|
+
|
3
|
+
import <%= base_package %>.<%= application_name %>EntryPoint.<%= application_name %>Application;
|
4
|
+
import <%= base_package %>.<% if options[:session] -%>Session<% end -%>ActivityPlaceActivityMapper;
|
5
|
+
<% if options[:session] -%>
|
6
|
+
import <%= activities_package %>.LoginActivity;
|
7
|
+
<% end -%>
|
8
|
+
import <%= gwt_rails_package %>.Application;
|
9
|
+
import <%= gwt_rails_package %>.BaseModule;
|
10
|
+
|
11
|
+
import com.google.gwt.activity.shared.Activity;
|
12
|
+
import com.google.gwt.activity.shared.ActivityMapper;
|
13
|
+
import com.google.gwt.core.client.GWT;
|
14
|
+
import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder;
|
15
|
+
import com.google.inject.Provider;
|
16
|
+
import com.google.inject.Singleton;
|
17
|
+
import com.google.inject.name.Names;
|
18
|
+
|
19
|
+
<% if options[:session] -%>
|
20
|
+
import <%= views_package %>.LoginViewImpl;
|
21
|
+
|
22
|
+
import <%= gwt_rails_session_package %>.LoginView;
|
23
|
+
<% end -%>
|
24
|
+
public class <%= application_name %>Module extends BaseModule {
|
25
|
+
|
26
|
+
@Override
|
27
|
+
protected void configure() {
|
28
|
+
super.configure();
|
29
|
+
bind(Application.class).to(<%= application_name %>Application.class);
|
30
|
+
bind(ActivityMapper.class).to(<% if options[:session] -%>Session<% end -%>ActivityPlaceActivityMapper.class).in(Singleton.class);
|
31
|
+
<% if options[:session] -%>
|
32
|
+
bind(LoginView.class).to(LoginViewImpl.class);
|
33
|
+
<% end -%>
|
34
|
+
install(new GinFactoryModuleBuilder()
|
35
|
+
<% if options[:session] -%>
|
36
|
+
.implement(Activity.class, Names.named("login"), LoginActivity.class)
|
37
|
+
<% end -%>
|
38
|
+
.build(ActivityFactory.class));
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
package <%= activities_package %>;
|
2
|
+
|
3
|
+
import javax.inject.Inject;
|
4
|
+
|
5
|
+
import <%= models_package %>.User;
|
6
|
+
import <%= places_package %>.LoginPlace;
|
7
|
+
import <%= restservices_package %>.SessionRestService;
|
8
|
+
|
9
|
+
import org.fusesource.restygwt.client.Method;
|
10
|
+
import org.fusesource.restygwt.client.MethodCallback;
|
11
|
+
|
12
|
+
import com.google.gwt.activity.shared.AbstractActivity;
|
13
|
+
import com.google.gwt.core.client.GWT;
|
14
|
+
import com.google.gwt.event.shared.EventBus;
|
15
|
+
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
16
|
+
import com.google.inject.assistedinject.Assisted;
|
17
|
+
|
18
|
+
import <%= gwt_rails_session_package %>.Authentication;
|
19
|
+
import <%= gwt_rails_session_package %>.LoginView;
|
20
|
+
import <%= gwt_rails_session_package %>.Session;
|
21
|
+
import <%= gwt_rails_session_package %>.SessionManager;
|
22
|
+
|
23
|
+
public class LoginActivity extends AbstractActivity implements LoginView.Presenter{
|
24
|
+
|
25
|
+
private final SessionRestService service;
|
26
|
+
private final LoginView view;
|
27
|
+
private final SessionManager<User> sessionManager;
|
28
|
+
|
29
|
+
@Inject
|
30
|
+
public LoginActivity(@Assisted LoginPlace place,
|
31
|
+
LoginView view,
|
32
|
+
SessionRestService service,
|
33
|
+
SessionManager<User> sessionManager) {
|
34
|
+
this.view = view;
|
35
|
+
this.service = service;
|
36
|
+
this.sessionManager = sessionManager;
|
37
|
+
}
|
38
|
+
|
39
|
+
public void start(AcceptsOneWidget display, EventBus eventBus) {
|
40
|
+
display.setWidget(view.asWidget());
|
41
|
+
view.setPresenter(this);
|
42
|
+
}
|
43
|
+
|
44
|
+
public void login(final String login, String password) {
|
45
|
+
Authentication authentication = new Authentication(login, password);
|
46
|
+
service.create(authentication, new MethodCallback<Session<User>>() {
|
47
|
+
|
48
|
+
public void onSuccess(Method method, Session<User> session) {
|
49
|
+
GWT.log("logged in: " + login);
|
50
|
+
sessionManager.login(session);
|
51
|
+
}
|
52
|
+
|
53
|
+
public void onFailure(Method method, Throwable exception) {
|
54
|
+
GWT.log("login failed: " + exception.getMessage(), exception);
|
55
|
+
sessionManager.accessDenied();
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}
|
59
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
package <%= places_package %>;
|
2
|
+
|
3
|
+
import <%= base_package %>.ActivityPlace;
|
4
|
+
import <%= managed_package %>.ActivityFactory;
|
5
|
+
|
6
|
+
import com.google.gwt.activity.shared.Activity;
|
7
|
+
|
8
|
+
public class LoginPlace extends ActivityPlace {
|
9
|
+
|
10
|
+
public static final LoginPlace LOGIN = new LoginPlace();
|
11
|
+
|
12
|
+
private LoginPlace() {
|
13
|
+
super(null);
|
14
|
+
}
|
15
|
+
|
16
|
+
@Override
|
17
|
+
public Activity create(ActivityFactory factory) {
|
18
|
+
return factory.create(this);
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
2
|
+
<ui:UiBinder
|
3
|
+
xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
4
|
+
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
5
|
+
|
6
|
+
<ui:style>
|
7
|
+
</ui:style>
|
8
|
+
|
9
|
+
<g:SimplePanel>
|
10
|
+
<g:VerticalPanel>
|
11
|
+
<g:InlineHTML>username</g:InlineHTML>
|
12
|
+
<g:TextBox ui:field="username"/>
|
13
|
+
<g:InlineHTML>password</g:InlineHTML>
|
14
|
+
<g:PasswordTextBox ui:field="password"/>
|
15
|
+
<g:Button ui:field="loginButton">login</g:Button>
|
16
|
+
</g:VerticalPanel>
|
17
|
+
</g:SimplePanel>
|
18
|
+
</ui:UiBinder>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
package <%= views_package %>;
|
2
|
+
|
3
|
+
import com.google.gwt.core.client.GWT;
|
4
|
+
import com.google.gwt.uibinder.client.UiBinder;
|
5
|
+
import com.google.gwt.uibinder.client.UiTemplate;
|
6
|
+
import com.google.gwt.user.client.ui.Widget;
|
7
|
+
import com.google.inject.Singleton;
|
8
|
+
|
9
|
+
@Singleton
|
10
|
+
public class LoginViewImpl extends <%= gwt_rails_session_package %>.LoginViewImpl {
|
11
|
+
|
12
|
+
@UiTemplate("LoginView.ui.xml")
|
13
|
+
interface LoginViewUiBinder extends UiBinder<Widget,<%= gwt_rails_session_package %>.LoginViewImpl> {}
|
14
|
+
|
15
|
+
private static LoginViewUiBinder uiBinder = GWT.create(LoginViewUiBinder.class);
|
16
|
+
|
17
|
+
public LoginViewImpl() {
|
18
|
+
super(uiBinder);
|
19
|
+
}
|
20
|
+
|
21
|
+
}
|
@@ -1,9 +1,12 @@
|
|
1
1
|
#-*- mode: ruby -*-
|
2
|
-
|
2
|
+
GWT_VERSION = '2.2.0'
|
3
|
+
jar('org.fusesource.restygwt:restygwt', '1.2-SNAPSHOT').scope :provided
|
3
4
|
jar('javax.ws.rs:jsr311-api', '1.1').scope :provided
|
4
|
-
jar('com.google.gwt:gwt-user',
|
5
|
+
jar('com.google.gwt:gwt-user', GWT_VERSION).scope :provided
|
6
|
+
jar('com.google.gwt.inject:gin', '1.5.0').scope :provided
|
7
|
+
jar('de.mkristian.rails-gwt:rails-gwt', '0.1.0-SNAPSHOT').scope :provided
|
5
8
|
|
6
|
-
plugin('org.codehaus.mojo:gwt-maven-plugin',
|
9
|
+
plugin('org.codehaus.mojo:gwt-maven-plugin', GWT_VERSION) do |gwt|
|
7
10
|
gwt.with({ :warSourceDirectory => "${basedir}/public",
|
8
11
|
:webXml => "${basedir}/public/WEB-INF/web.xml",
|
9
12
|
:webappDirectory => "${basedir}/public",
|
@@ -18,7 +21,6 @@ plugin('org.codehaus.mojo:gwt-maven-plugin', '2.2.0') do |gwt|
|
|
18
21
|
})
|
19
22
|
gwt.executions.goals << ["clean", "compile", "test"]
|
20
23
|
end
|
21
|
-
plugin(:bundler, "${jruby.plugins.version}").execution.goals << :install
|
22
24
|
plugin(:rails3).in_phase("initialize").execute_goal(:pom).with :force => true
|
23
25
|
|
24
26
|
#-- Macs need the -d32 -XstartOnFirstThread jvm options -->
|
@@ -27,4 +29,5 @@ profile("mac") do |mac|
|
|
27
29
|
mac.plugin('org.codehaus.mojo:gwt-maven-plugin').with(:extraJvmArgs => "-d32 -XstartOnFirstThread -Xmx512m")
|
28
30
|
end
|
29
31
|
|
32
|
+
repository(:snapshots).url "http://mojo.saumya.de"
|
30
33
|
# vim: syntax=Ruby
|
@@ -0,0 +1,24 @@
|
|
1
|
+
package <%= managed_package %>;
|
2
|
+
|
3
|
+
import <%= gwt_rails_package %>.RestfulAction;
|
4
|
+
|
5
|
+
public abstract class RestfulPlace<T> extends ActivityPlace {
|
6
|
+
|
7
|
+
public final RestfulAction action;
|
8
|
+
|
9
|
+
private T resource;
|
10
|
+
|
11
|
+
public RestfulPlace(RestfulAction restfulAction) {
|
12
|
+
this.action = restfulAction;
|
13
|
+
}
|
14
|
+
|
15
|
+
public void setResource(T resource) {
|
16
|
+
if (this.resource == null) {
|
17
|
+
this.resource = resource;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
public T getResource() {
|
22
|
+
return resource;
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
package <%= base_package %>;
|
2
|
+
|
3
|
+
import javax.inject.Inject;
|
4
|
+
|
5
|
+
import <%= managed_package %>.ActivityFactory;
|
6
|
+
import <%= models_package %>.User;
|
7
|
+
import <%= places_package %>.LoginPlace;
|
8
|
+
|
9
|
+
import com.google.gwt.activity.shared.Activity;
|
10
|
+
import com.google.gwt.place.shared.Place;
|
11
|
+
|
12
|
+
import de.mkristian.gwt.rails.Notice;
|
13
|
+
import de.mkristian.gwt.rails.RestfulPlace;
|
14
|
+
import de.mkristian.gwt.rails.session.NeedsAuthorization;
|
15
|
+
import de.mkristian.gwt.rails.session.NoAuthorization;
|
16
|
+
import de.mkristian.gwt.rails.session.SessionManager;
|
17
|
+
|
18
|
+
public class SessionActivityPlaceActivityMapper extends ActivityPlaceActivityMapper {
|
19
|
+
|
20
|
+
private final SessionManager<User> manager;
|
21
|
+
|
22
|
+
@Inject
|
23
|
+
public SessionActivityPlaceActivityMapper(ActivityFactory factory, SessionManager<User> manager, Notice notice) {
|
24
|
+
super(factory, notice);
|
25
|
+
this.manager = manager;
|
26
|
+
}
|
27
|
+
|
28
|
+
public Activity getActivity(Place place) {
|
29
|
+
return pessimisticGetActivity(place);
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* pessimistic in the sense that default is authorisation, only the places
|
34
|
+
* which implements {@link NoAuthorization} will be omitted by the check.
|
35
|
+
*/
|
36
|
+
protected Activity pessimisticGetActivity(Place place) {
|
37
|
+
if (!(place instanceof NoAuthorization)) {
|
38
|
+
if(manager.isActive()){
|
39
|
+
if(!manager.isAllowed((RestfulPlace)place)){
|
40
|
+
notice.setText("nothing to see");
|
41
|
+
return null;
|
42
|
+
}
|
43
|
+
//TODO move into a dispatch filter or callback filter
|
44
|
+
manager.resetTimer();
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
return LoginPlace.LOGIN.create(factory);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return super.getActivity(place);
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* optimistic in the sense that default is no authorisation, only the places
|
55
|
+
* which implements {@link NeedsAuthorization} will be checked.
|
56
|
+
*/
|
57
|
+
protected Activity optimisticGetActivity(Place place) {
|
58
|
+
if (place instanceof NeedsAuthorization) {
|
59
|
+
if(manager.isActive()){
|
60
|
+
if(!manager.isAllowed((RestfulPlace)place)){
|
61
|
+
notice.setText("nothing to see");
|
62
|
+
return null;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
else {
|
66
|
+
return LoginPlace.LOGIN.create(factory);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
return super.getActivity(place);
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
package <%= restservices_package %>;
|
2
|
+
|
3
|
+
import javax.ws.rs.DELETE;
|
4
|
+
import javax.ws.rs.POST;
|
5
|
+
import javax.ws.rs.Path;
|
6
|
+
|
7
|
+
import <%= models_package %>.User;
|
8
|
+
|
9
|
+
import org.fusesource.restygwt.client.MethodCallback;
|
10
|
+
import org.fusesource.restygwt.client.RestService;
|
11
|
+
|
12
|
+
import <%= gwt_rails_session_package %>.Authentication;
|
13
|
+
import <%= gwt_rails_session_package %>.Session;
|
14
|
+
|
15
|
+
@Path("/session")
|
16
|
+
public interface SessionRestService extends RestService {
|
17
|
+
|
18
|
+
@POST
|
19
|
+
void create(Authentication authentication, MethodCallback<Session<User>> callback);
|
20
|
+
|
21
|
+
@DELETE
|
22
|
+
void destroy(MethodCallback<Void> callback);
|
23
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
.notice
|
2
|
+
{
|
3
|
+
background-color:lightgoldenRodYellow;
|
4
|
+
border:1px solid darkgoldenrod;
|
5
|
+
color:darkgoldenrod;
|
6
|
+
margin-left:35%;
|
7
|
+
margin-right:35%;
|
8
|
+
padding-left:5%;
|
9
|
+
width:30%;
|
10
|
+
padding-right:5%;
|
11
|
+
padding-top:.5em;
|
12
|
+
padding-bottom:.5em;
|
13
|
+
overflow:auto;;
|
14
|
+
position:absolute;
|
15
|
+
top:3em;
|
16
|
+
opacity:.9;
|
17
|
+
}
|