├── .gitignore
├── CHANGE.md
├── LICENSE
├── README.md
├── TODO.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── main.js
│ └── paste.js
│ ├── java
│ └── github
│ │ └── hotstu
│ │ └── lu
│ │ ├── App.java
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── base
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── github
│ │ └── hotstu
│ │ └── lu
│ │ └── base
│ │ ├── IPlayCallback.aidl
│ │ └── IPlayService.aidl
│ └── java
│ └── github
│ └── hotstu
│ └── lu
│ └── base
│ └── IModule.java
├── build.gradle
├── demo.gif
├── engine
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── init.js
│ ├── java
│ └── github
│ │ └── hotstu
│ │ └── lu
│ │ └── engine
│ │ ├── AssetAndUrlModuleSourceProvider.java
│ │ ├── ConsoleImpl.java
│ │ ├── DefaultLuContext.java
│ │ ├── LuContext.java
│ │ ├── LuEngine.java
│ │ ├── LuEngineThread.java
│ │ ├── ModuleApp.java
│ │ └── ScriptTask.java
│ └── resources
│ └── META-INF
│ └── services
│ └── github.hotstu.lu.base.IModule
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── play
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── form.html
│ └── web
│ │ ├── addon
│ │ ├── comment
│ │ │ ├── comment.js
│ │ │ └── continuecomment.js
│ │ ├── dialog
│ │ │ ├── dialog.css
│ │ │ └── dialog.js
│ │ ├── display
│ │ │ ├── autorefresh.js
│ │ │ ├── fullscreen.css
│ │ │ ├── fullscreen.js
│ │ │ ├── panel.js
│ │ │ ├── placeholder.js
│ │ │ └── rulers.js
│ │ ├── edit
│ │ │ ├── closebrackets.js
│ │ │ ├── closetag.js
│ │ │ ├── continuelist.js
│ │ │ ├── matchbrackets.js
│ │ │ ├── matchtags.js
│ │ │ └── trailingspace.js
│ │ ├── fold
│ │ │ ├── brace-fold.js
│ │ │ ├── comment-fold.js
│ │ │ ├── foldcode.js
│ │ │ ├── foldgutter.css
│ │ │ ├── foldgutter.js
│ │ │ ├── indent-fold.js
│ │ │ ├── markdown-fold.js
│ │ │ └── xml-fold.js
│ │ ├── hint
│ │ │ ├── anyword-hint.js
│ │ │ ├── css-hint.js
│ │ │ ├── html-hint.js
│ │ │ ├── javascript-hint.js
│ │ │ ├── show-hint.css
│ │ │ ├── show-hint.js
│ │ │ ├── sql-hint.js
│ │ │ └── xml-hint.js
│ │ ├── lint
│ │ │ ├── coffeescript-lint.js
│ │ │ ├── css-lint.js
│ │ │ ├── html-lint.js
│ │ │ ├── javascript-lint.js
│ │ │ ├── json-lint.js
│ │ │ ├── lint.css
│ │ │ ├── lint.js
│ │ │ └── yaml-lint.js
│ │ ├── merge
│ │ │ ├── merge.css
│ │ │ └── merge.js
│ │ ├── mode
│ │ │ ├── loadmode.js
│ │ │ ├── multiplex.js
│ │ │ ├── multiplex_test.js
│ │ │ ├── overlay.js
│ │ │ └── simple.js
│ │ ├── runmode
│ │ │ ├── colorize.js
│ │ │ ├── runmode-standalone.js
│ │ │ ├── runmode.js
│ │ │ └── runmode.node.js
│ │ ├── scroll
│ │ │ ├── annotatescrollbar.js
│ │ │ ├── scrollpastend.js
│ │ │ ├── simplescrollbars.css
│ │ │ └── simplescrollbars.js
│ │ ├── search
│ │ │ ├── jump-to-line.js
│ │ │ ├── match-highlighter.js
│ │ │ ├── matchesonscrollbar.css
│ │ │ ├── matchesonscrollbar.js
│ │ │ ├── search.js
│ │ │ └── searchcursor.js
│ │ ├── selection
│ │ │ ├── active-line.js
│ │ │ ├── mark-selection.js
│ │ │ └── selection-pointer.js
│ │ ├── tern
│ │ │ ├── tern.css
│ │ │ ├── tern.js
│ │ │ └── worker.js
│ │ └── wrap
│ │ │ └── hardwrap.js
│ │ ├── lib
│ │ ├── codemirror.css
│ │ └── codemirror.js
│ │ ├── mode
│ │ ├── index.html
│ │ ├── javascript
│ │ │ ├── index.html
│ │ │ ├── javascript.js
│ │ │ ├── json-ld.html
│ │ │ ├── test.js
│ │ │ └── typescript.html
│ │ └── meta.js
│ │ └── theme
│ │ ├── darcula.css
│ │ └── monokai.css
│ ├── java
│ └── github
│ │ └── hotstu
│ │ └── lu
│ │ └── play
│ │ ├── Function.java
│ │ ├── HttpDaemonService.java
│ │ ├── ModuleApp.java
│ │ ├── ServerApp.java
│ │ └── StaticHandler.java
│ ├── res
│ └── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ └── resources
│ └── META-INF
│ └── services
│ └── github.hotstu.lu.base.IModule
├── render
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── modules
│ │ ├── ShadowModule.js
│ │ ├── h.js
│ │ ├── phatomDomAPI.js
│ │ ├── snabbdom-attributes.js
│ │ ├── snabbdom-class.js
│ │ ├── snabbdom-dataset.js
│ │ ├── snabbdom-eventlisteners.js
│ │ ├── snabbdom-patch.js
│ │ ├── snabbdom-props.js
│ │ ├── snabbdom-style.js
│ │ ├── snabbdom.js
│ │ └── tovnode.js
│ ├── java
│ └── github
│ │ └── hotstu
│ │ └── lu
│ │ └── render
│ │ ├── NativeComponent.java
│ │ ├── NativeRenderAPI.java
│ │ ├── RenderContext.java
│ │ ├── component
│ │ ├── Comment.java
│ │ ├── Frame.java
│ │ └── Text.java
│ │ ├── event
│ │ ├── Event.java
│ │ └── LuClickHandler.java
│ │ ├── module
│ │ └── ClassManager.java
│ │ ├── style
│ │ └── SimpleStyleEngine.java
│ │ └── widget
│ │ └── LuLinearLayout.java
│ └── res
│ └── values
│ └── ids.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 |
--------------------------------------------------------------------------------
/CHANGE.md:
--------------------------------------------------------------------------------
1 | ### 1.0.0
2 |
3 | * init
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Lu-Another
2 | ======================
3 |
4 | [Lu-Another]是一款我用业余时间开发的的
5 |
6 | 基于Virtual DOM的原生UI渲染框架
7 |
8 | 类似[Weex]、[ReactNative],
9 |
10 | 但不是对他们的复制,而是独立开发从底层写起
11 |
12 | 设计开发理念是实现一个极简的, 界面渲染各种业务逻辑全部在JS中, 实现了App的动态化。
13 |
14 |
15 | 虽然无法和大公司的成熟框架相比,但他内部的原理是相通的
16 |
17 | 研究学习探索的过程也是不断自我成长的过程
18 |
19 | 在这个这个项目开发过程中不仅实现了virtualDom的渲染引擎
20 |
21 | 还实现了基于web的原生界面编辑器(可以在浏览器中编辑界面在手机中实时看到渲染效果)
22 |
23 | 封装了Rhino Js引擎
24 |
25 | 掌握了Android中动态加载动态Class的技术
26 |
27 | 基于AIDL的模块化技术
28 |
29 |
30 | # demo使用方式
31 |
32 | 手机、PC连接在同一wifi下, 启动App, PC访问`http://手机ip:8080/`
33 |
34 | (如果手机为模拟器, 需要先执行`adb -e forward tcp:8080 tcp:8080`, 然后访问`http://127.0.0.1:8080/`)
35 |
36 |
37 | # 运行效果
38 |
39 |
40 |
41 |
42 |
43 | ## more about me
44 |
45 | |简书| 掘金|JCenter | dockerHub|
46 | | ------------- |------------- |------------- |------------- |
47 | | [简书](https://www.jianshu.com/u/ca2207af2001) | [掘金](https://juejin.im/user/5bee320651882516be2ebbfe) |[JCenter ](https://bintray.com/hglf/maven) | [dockerHub](https://hub.docker.com/u/hglf)|
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TODO:
5 |
6 |
7 | [x] 线程优化(工作线程、渲染线程、ui线程)
8 |
9 | [x] 支持Class (需要同时支持setAttribute 和classList.add, 可能需要重写module)
10 |
11 | [] 支持property(使用注解预编译)
12 |
13 | [] 多媒体支持(图片视频)
14 |
15 | [] 列表渲染
16 |
17 | [] 表单, 双向绑定
18 |
19 | [] 支持Style(参考jss, 支持css的子集)
20 |
21 | [] 支持v8引擎
22 |
23 | [] 支持自定义view
24 |
25 | [] 使用Litho 作为组件基础库
26 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "30.0.2"
6 | compileOptions {
7 | sourceCompatibility 1.8
8 | targetCompatibility 1.8
9 | }
10 | defaultConfig {
11 | applicationId "github.hotstu.lu"
12 | minSdkVersion 22
13 | targetSdkVersion 29
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: "libs", include: ["*.jar"])
30 | implementation 'androidx.appcompat:appcompat:1.2.0'
31 | implementation project(path: ':base')
32 | implementation project(path: ':play')
33 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
34 | implementation project(path: ':engine')
35 | implementation project(path: ':render')
36 | implementation("com.squareup.okio:okio:2.8.0")
37 |
38 | testImplementation 'junit:junit:4.12'
39 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
41 |
42 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/github/hotstu/lu/App.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu;
2 |
3 | import android.app.Application;
4 |
5 | import java.util.Iterator;
6 | import java.util.ServiceLoader;
7 |
8 | import github.hotstu.lu.base.IModule;
9 |
10 | /**
11 | * @author hglf [hglf](https://github.com/hotstu)
12 | * @desc
13 | * @since 9/16/20
14 | */
15 | public class App extends Application {
16 | @Override
17 | public void onCreate() {
18 | super.onCreate();
19 | ServiceLoader load = ServiceLoader.load(IModule.class);
20 | Iterator iterator = load.iterator();
21 | while (iterator.hasNext()) {
22 | try {
23 | IModule next = iterator.next();
24 | next.onCreate(this);
25 | } catch (Exception e) {
26 | e.printStackTrace();
27 | }
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/github/hotstu/lu/MainActivity.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.RemoteException;
9 | import android.util.Log;
10 |
11 | import androidx.appcompat.app.AppCompatActivity;
12 |
13 | import java.io.BufferedInputStream;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 |
17 | import github.hotstu.lu.base.IPlayCallback;
18 | import github.hotstu.lu.base.IPlayService;
19 | import github.hotstu.lu.engine.LuEngine;
20 | import github.hotstu.lu.play.HttpDaemonService;
21 | import github.hotstu.lu.render.RenderContext;
22 | import okio.ByteString;
23 |
24 | public class MainActivity extends AppCompatActivity {
25 |
26 | private ServiceConnection conn;
27 | private EventHandler mEventHandler = new EventHandler();
28 | private IPlayService engineService;
29 | private RenderContext defaultContext;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 | LuEngine.getInstance().start();
36 | defaultContext = new RenderContext(this, "root");
37 | try {
38 | defaultContext.resetContextScope().await();
39 | } catch (InterruptedException e) {
40 | e.printStackTrace();
41 | }
42 | defaultContext.wrap(findViewById(R.id.root));
43 | InputStream open = null;
44 | try {
45 | open = new BufferedInputStream(getAssets().open("main.js"));
46 | ByteString read = ByteString.read(open, open.available());
47 | defaultContext.exec(read.utf8());
48 | } catch (IOException e) {
49 | e.printStackTrace();
50 | } finally {
51 | if (open != null) {
52 | try {
53 | open.close();
54 | } catch (IOException e) {
55 | e.printStackTrace();
56 | }
57 | }
58 | }
59 |
60 | bindService();
61 | }
62 |
63 | public class EventHandler extends IPlayCallback.Stub {
64 | public EventHandler() {
65 | }
66 |
67 | @Override
68 | public Bundle onEvent(int what, String msg) throws RemoteException {
69 | Log.d("MainActivity", Thread.currentThread().getName() + "event=>" + msg);
70 | return defaultContext.exec(msg);
71 | }
72 | }
73 |
74 |
75 | private void bindService() {
76 | Intent i = new Intent(this, HttpDaemonService.class);
77 | conn = new ServiceConnection() {
78 | @Override
79 | public void onServiceConnected(ComponentName name, IBinder service) {
80 | engineService = IPlayService.Stub.asInterface(service);
81 | try {
82 | engineService.setCallback(mEventHandler);
83 | } catch (RemoteException e) {
84 | e.printStackTrace();
85 | }
86 | }
87 |
88 | @Override
89 | public void onServiceDisconnected(ComponentName name) {
90 |
91 | }
92 |
93 | @Override
94 | public void onBindingDied(ComponentName name) {
95 | unbindService(this);
96 |
97 | bindService();
98 | }
99 | };
100 | bindService(i, conn, BIND_AUTO_CREATE);
101 | }
102 |
103 | @Override
104 | protected void onDestroy() {
105 | if (engineService != null) {
106 | try {
107 | engineService.setCallback(null);
108 | } catch (RemoteException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | unbindService(conn);
113 | LuEngine.getInstance().shutDown();
114 | super.onDestroy();
115 | }
116 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | lu
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/base/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "30.0.2"
6 | compileOptions {
7 | sourceCompatibility 1.8
8 | targetCompatibility 1.8
9 | }
10 | defaultConfig {
11 | minSdkVersion 22
12 | targetSdkVersion 29
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: "libs", include: ["*.jar"])
29 | implementation 'androidx.appcompat:appcompat:1.2.0'
30 |
31 | }
--------------------------------------------------------------------------------
/base/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/base/consumer-rules.pro
--------------------------------------------------------------------------------
/base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/base/src/main/aidl/github/hotstu/lu/base/IPlayCallback.aidl:
--------------------------------------------------------------------------------
1 | // ICallback.aidl
2 | package github.hotstu.lu.base;
3 |
4 | // Declare any non-default types here with import statements
5 |
6 | interface IPlayCallback {
7 | /**
8 | * Demonstrates some basic types that you can use as parameters
9 | * and return values in AIDL.
10 | */
11 | Bundle onEvent(int what, String msg);
12 | }
13 |
--------------------------------------------------------------------------------
/base/src/main/aidl/github/hotstu/lu/base/IPlayService.aidl:
--------------------------------------------------------------------------------
1 | // IEngineService.aidl
2 | package github.hotstu.lu.base;
3 |
4 | import github.hotstu.lu.base.IPlayCallback;
5 |
6 | interface IPlayService {
7 |
8 | void setCallback(IPlayCallback callback);
9 | }
10 |
--------------------------------------------------------------------------------
/base/src/main/java/github/hotstu/lu/base/IModule.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.base;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * @author hglf [hglf](https://github.com/hotstu)
7 | * @desc
8 | * @since 9/16/20
9 | */
10 | public interface IModule {
11 | void onCreate(Context context);
12 | }
13 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:4.0.1"
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | task clean(type: Delete) {
20 | delete rootProject.buildDir
21 | }
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/demo.gif
--------------------------------------------------------------------------------
/engine/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/engine/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "30.0.2"
6 | compileOptions {
7 | sourceCompatibility 1.8
8 | targetCompatibility 1.8
9 | }
10 | defaultConfig {
11 | minSdkVersion 22
12 | targetSdkVersion 29
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: "libs", include: ["*.jar"])
29 | implementation 'androidx.appcompat:appcompat:1.2.0'
30 | implementation 'com.faendir.rhino:rhino-android:1.5.2'
31 | implementation group: 'org.mozilla', name: 'rhino', version: '1.7.12'
32 | implementation project(path: ':base')
33 |
34 | }
--------------------------------------------------------------------------------
/engine/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/engine/consumer-rules.pro
--------------------------------------------------------------------------------
/engine/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/engine/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
--------------------------------------------------------------------------------
/engine/src/main/assets/init.js:
--------------------------------------------------------------------------------
1 | var global = this;
2 |
3 |
4 | (function () {
5 | //重定向importClass使得其支持字符串参数
6 | global.importClass =
7 | (function () {
8 | var __importClass__ = importClass;
9 | return function (pack) {
10 | if (typeof (pack) == "string") {
11 | __importClass__(Packages[pack]);
12 | } else {
13 | __importClass__(pack);
14 | }
15 | }
16 | })();
17 | })();
18 |
19 |
20 |
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/AssetAndUrlModuleSourceProvider.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import android.content.res.AssetManager;
4 |
5 | import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
6 | import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
7 |
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 | import java.net.URI;
12 | import java.net.URISyntaxException;
13 | import java.util.List;
14 |
15 |
16 | public class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
17 |
18 | private final URI mBaseURI;
19 | private final String mAssetDirPath;
20 | private final AssetManager mAssetManager;
21 |
22 | public AssetAndUrlModuleSourceProvider(String assetDirPath, List list) {
23 | super(list, null);
24 | mAssetDirPath = assetDirPath;
25 | mBaseURI = URI.create("file:///android_asset/" + assetDirPath);
26 | mAssetManager = ModuleApp.application.getAssets();
27 | }
28 |
29 | @Override
30 | protected ModuleSource loadFromPrivilegedLocations(String moduleId, Object validator) throws IOException, URISyntaxException {
31 | String moduleIdWithExtension = moduleId;
32 | if (!moduleIdWithExtension.endsWith(".js")) {
33 | moduleIdWithExtension += ".js";
34 | }
35 | try {
36 | return new ModuleSource(new InputStreamReader(mAssetManager.open(mAssetDirPath + "/" + moduleIdWithExtension)), null,
37 | new URI(mBaseURI.toString() + "/" + moduleIdWithExtension), mBaseURI, validator);
38 | } catch (FileNotFoundException e) {
39 | return super.loadFromPrivilegedLocations(moduleId, validator);
40 | }
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/ConsoleImpl.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * @author hglf [hglf](https://github.com/hotstu)
7 | * @desc
8 | * @since 9/10/20
9 | */
10 | public class ConsoleImpl {
11 | public void log(Object... objects) {
12 | StringBuilder sb = new StringBuilder();
13 | for (Object object : objects) {
14 | sb.append(object);
15 | sb.append(',');
16 | }
17 | sb.delete(sb.length() - 1, sb.length());
18 | Log.d("Console", sb.toString());
19 | }
20 |
21 | public void error(Object... objects) {
22 | StringBuilder sb = new StringBuilder();
23 | for (Object object : objects) {
24 | sb.append(object);
25 | sb.append(',');
26 | }
27 | sb.delete(sb.length() - 1, sb.length());
28 | Log.e("Console", sb.toString());
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/DefaultLuContext.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import org.mozilla.javascript.Scriptable;
4 |
5 | /**
6 | * @author hglf [hglf](https://github.com/hotstu)
7 | * @desc
8 | * @since 9/18/20
9 | */
10 | public class DefaultLuContext extends LuContext {
11 | public DefaultLuContext(Scriptable sharedScope) {
12 | super(sharedScope);
13 | }
14 |
15 | @Override
16 | protected void onContextScopeCreated(Scriptable scope) {
17 | LuEngine.getInstance().putProperty(scope, "$app", ModuleApp.application);
18 | LuEngine.getInstance().putProperty(scope, "$context", this);
19 |
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/LuContext.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import android.os.Bundle;
4 |
5 | import org.mozilla.javascript.Context;
6 | import org.mozilla.javascript.Scriptable;
7 |
8 | import java.util.concurrent.CountDownLatch;
9 |
10 | /**
11 | * @author hglf [hglf](https://github.com/hotstu)
12 | * @desc
13 | * @since 9/16/20
14 | */
15 | public abstract class LuContext {
16 |
17 | private Scriptable mContextScope;
18 | private final Scriptable mShared;
19 |
20 | public LuContext() {
21 | this.mShared = LuEngine.getInstance().getSharedScope();
22 | }
23 | public LuContext(Scriptable sharedScope) {
24 | this.mShared = sharedScope;
25 | }
26 |
27 | public Scriptable getContextScope() {
28 | return mContextScope;
29 | }
30 |
31 |
32 | public CountDownLatch resetContextScope() {
33 | CountDownLatch countDownLatch = new CountDownLatch(1);
34 | LuEngine.getInstance().getWorkerHandler().post(() -> {
35 | this.mContextScope = resetContextScope(mShared);
36 | this.onContextScopeCreated(this.mContextScope);
37 | countDownLatch.countDown();
38 | });
39 | return countDownLatch;
40 | }
41 |
42 |
43 | protected abstract void onContextScopeCreated(Scriptable scope);
44 |
45 |
46 | public Bundle exec(String script) {
47 | ScriptTask task = new ScriptTask(this, script);
48 | LuEngine.getInstance().enqueueTask(task);
49 | task.await(3*1000);
50 | Bundle bundle = new Bundle();
51 | bundle.putBoolean("success", task.err == null);
52 | bundle.putString("data", task.output);
53 | bundle.putString("err", task.err);
54 | return bundle;
55 | }
56 |
57 | private Scriptable resetContextScope(Scriptable shared) {
58 | LuEngine.getInstance().enforceWorkerThread();
59 | // We can share the scope.
60 | Scriptable threadScope = Context.getCurrentContext().newObject(shared);
61 | threadScope.setPrototype(shared);
62 |
63 | // We want "threadScope" to be a new top-level
64 | // scope, so set its parent scope to null. This
65 | // means that any variables created by assignments
66 | // will be properties of "threadScope".
67 | threadScope.setParentScope(null);
68 | return threadScope;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/LuEngineThread.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import android.os.HandlerThread;
4 |
5 | import com.faendir.rhino_android.RhinoAndroidHelper;
6 |
7 | import org.mozilla.javascript.Context;
8 | import org.mozilla.javascript.Scriptable;
9 | import org.mozilla.javascript.WrapFactory;
10 |
11 | import java.util.Locale;
12 |
13 | public class LuEngineThread extends HandlerThread {
14 |
15 | public LuEngineThread(String name) {
16 | super(name);
17 | }
18 |
19 | public LuEngineThread(String name, int priority) {
20 | super(name, priority);
21 | }
22 |
23 | @Override
24 | protected void onLooperPrepared() {
25 | super.onLooperPrepared();
26 | init();
27 | }
28 |
29 |
30 | public void init() {
31 | if (Context.getCurrentContext() == null) {
32 | Context context = RhinoAndroidHelper.prepareContext();
33 | context.setOptimizationLevel(1);//TODO 大于0 == JIT
34 | context.setLanguageVersion(Context.VERSION_ES6);
35 | context.setLocale(Locale.getDefault());
36 | context.setWrapFactory(new WrapFactory() {
37 | @Override
38 | public Object wrap(Context cx, Scriptable scope, Object obj, Class> staticType) {
39 | return super.wrap(cx, scope, obj, staticType);
40 | }
41 |
42 | @Override
43 | public Scriptable wrapNewObject(Context cx, Scriptable scope, Object obj) {
44 | return super.wrapNewObject(cx, scope, obj);
45 | }
46 |
47 | @Override
48 | public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class> staticType) {
49 | return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
50 | }
51 |
52 | @Override
53 | public Scriptable wrapJavaClass(Context cx, Scriptable scope, Class> javaClass) {
54 | return super.wrapJavaClass(cx, scope, javaClass);
55 | }
56 | });
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/ModuleApp.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import android.content.Context;
4 |
5 | import github.hotstu.lu.base.IModule;
6 |
7 | /**
8 | * @author hglf [hglf](https://github.com/hotstu)
9 | * @desc
10 | * @since 9/16/20
11 | */
12 | public class ModuleApp implements IModule {
13 | public static Context application;
14 | @Override
15 | public void onCreate(Context context) {
16 | application = context;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/engine/src/main/java/github/hotstu/lu/engine/ScriptTask.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.engine;
2 |
3 | import java.util.concurrent.CountDownLatch;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | public class ScriptTask {
7 | public final String input;
8 | public final LuContext context;
9 | private final CountDownLatch lock;
10 | public String output = null;
11 | public String err = null;
12 |
13 |
14 | public ScriptTask(LuContext context, String input) {
15 | this.context = context;
16 | this.input = input;
17 | this.lock = new CountDownLatch(1);
18 | }
19 |
20 | public void await(long timeout) {
21 | try {
22 | lock.await(timeout, TimeUnit.MILLISECONDS);
23 | } catch (InterruptedException e) {
24 | e.printStackTrace();
25 | }
26 | }
27 |
28 | public void sendBack() {
29 | lock.countDown();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/engine/src/main/resources/META-INF/services/github.hotstu.lu.base.IModule:
--------------------------------------------------------------------------------
1 | github.hotstu.lu.engine.ModuleApp
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 16 14:13:00 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/play/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/play/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "30.0.2"
6 | compileOptions {
7 | sourceCompatibility 1.8
8 | targetCompatibility 1.8
9 | }
10 | defaultConfig {
11 | minSdkVersion 22
12 | targetSdkVersion 29
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: "libs", include: ["*.jar"])
29 | implementation 'androidx.appcompat:appcompat:1.2.0'
30 | implementation 'org.nanohttpd:nanohttpd:2.3.1'
31 | implementation 'com.google.code.gson:gson:2.8.6'
32 | implementation("com.squareup.okio:okio:2.8.0")
33 | implementation project(path: ':base')
34 | implementation project(path: ':engine')
35 |
36 | }
--------------------------------------------------------------------------------
/play/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/play/consumer-rules.pro
--------------------------------------------------------------------------------
/play/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/play/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/play/src/main/assets/form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Lu Play Groud
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 | 发送
29 | 清除日志
30 | 重置scope
31 |
32 |
35 |
36 |
37 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/comment/continuecomment.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | var nonspace = /\S/g;
13 | var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); };
14 | function continueComment(cm) {
15 | if (cm.getOption("disableInput")) return CodeMirror.Pass;
16 | var ranges = cm.listSelections(), mode, inserts = [];
17 | for (var i = 0; i < ranges.length; i++) {
18 | var pos = ranges[i].head
19 | if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass;
20 | var modeHere = cm.getModeAt(pos)
21 | if (!mode) mode = modeHere;
22 | else if (mode != modeHere) return CodeMirror.Pass;
23 |
24 | var insert = null, line, found;
25 | var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment;
26 | if (blockStart && mode.blockCommentContinue) {
27 | line = cm.getLine(pos.line);
28 | var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length);
29 | // 1. if this block comment ended
30 | // 2. if this is actually inside a line comment
31 | if (end != -1 && end == pos.ch - mode.blockCommentEnd.length ||
32 | lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 &&
33 | /\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) {
34 | // ...then don't continue it
35 | } else if (pos.ch >= blockStart.length &&
36 | (found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 &&
37 | found > end) {
38 | // reuse the existing leading spaces/tabs/mixed
39 | // or build the correct indent using CM's tab/indent options
40 | if (nonspaceAfter(0, line) >= found) {
41 | insert = line.slice(0, found);
42 | } else {
43 | var tabSize = cm.options.tabSize, numTabs;
44 | found = CodeMirror.countColumn(line, found, tabSize);
45 | insert = !cm.options.indentWithTabs ? repeat.call(" ", found) :
46 | repeat.call("\t", (numTabs = Math.floor(found / tabSize))) +
47 | repeat.call(" ", found - tabSize * numTabs);
48 | }
49 | } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 &&
50 | found <= pos.ch &&
51 | found <= nonspaceAfter(0, line)) {
52 | insert = line.slice(0, found);
53 | }
54 | if (insert != null) insert += mode.blockCommentContinue
55 | }
56 | if (insert == null && lineCmt && continueLineCommentEnabled(cm)) {
57 | if (line == null) line = cm.getLine(pos.line);
58 | found = line.indexOf(lineCmt);
59 | // cursor at pos 0, line comment also at pos 0 => shift it down, don't continue
60 | if (!pos.ch && !found) insert = "";
61 | // continue only if the line starts with an optional space + line comment
62 | else if (found > -1 && nonspaceAfter(0, line) >= found) {
63 | // don't continue if there's only space(s) after cursor or the end of the line
64 | insert = nonspaceAfter(pos.ch, line) > -1;
65 | // but always continue if the next line starts with a line comment too
66 | if (!insert) {
67 | var next = cm.getLine(pos.line + 1) || '',
68 | nextFound = next.indexOf(lineCmt);
69 | insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null;
70 | }
71 | if (insert) {
72 | insert = line.slice(0, found) + lineCmt +
73 | line.slice(found + lineCmt.length).match(/^\s*/)[0];
74 | }
75 | }
76 | }
77 | if (insert == null) return CodeMirror.Pass;
78 | inserts[i] = "\n" + insert;
79 | }
80 |
81 | cm.operation(function() {
82 | for (var i = ranges.length - 1; i >= 0; i--)
83 | cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
84 | });
85 | }
86 |
87 | function nonspaceAfter(ch, str) {
88 | nonspace.lastIndex = ch;
89 | var m = nonspace.exec(str);
90 | return m ? m.index : -1;
91 | }
92 |
93 | function continueLineCommentEnabled(cm) {
94 | var opt = cm.getOption("continueComments");
95 | if (opt && typeof opt == "object")
96 | return opt.continueLineComment !== false;
97 | return true;
98 | }
99 |
100 | CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
101 | if (prev && prev != CodeMirror.Init)
102 | cm.removeKeyMap("continueComment");
103 | if (val) {
104 | var key = "Enter";
105 | if (typeof val == "string")
106 | key = val;
107 | else if (typeof val == "object" && val.key)
108 | key = val.key;
109 | var map = {name: "continueComment"};
110 | map[key] = continueComment;
111 | cm.addKeyMap(map);
112 | }
113 | });
114 | });
115 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/dialog/dialog.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-dialog {
2 | position: absolute;
3 | left: 0; right: 0;
4 | background: inherit;
5 | z-index: 15;
6 | padding: .1em .8em;
7 | overflow: hidden;
8 | color: inherit;
9 | }
10 |
11 | .CodeMirror-dialog-top {
12 | border-bottom: 1px solid #eee;
13 | top: 0;
14 | }
15 |
16 | .CodeMirror-dialog-bottom {
17 | border-top: 1px solid #eee;
18 | bottom: 0;
19 | }
20 |
21 | .CodeMirror-dialog input {
22 | border: none;
23 | outline: none;
24 | background: transparent;
25 | width: 20em;
26 | color: inherit;
27 | font-family: monospace;
28 | }
29 |
30 | .CodeMirror-dialog button {
31 | font-size: 70%;
32 | }
33 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/autorefresh.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"))
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod)
9 | else // Plain browser env
10 | mod(CodeMirror)
11 | })(function(CodeMirror) {
12 | "use strict"
13 |
14 | CodeMirror.defineOption("autoRefresh", false, function(cm, val) {
15 | if (cm.state.autoRefresh) {
16 | stopListening(cm, cm.state.autoRefresh)
17 | cm.state.autoRefresh = null
18 | }
19 | if (val && cm.display.wrapper.offsetHeight == 0)
20 | startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
21 | })
22 |
23 | function startListening(cm, state) {
24 | function check() {
25 | if (cm.display.wrapper.offsetHeight) {
26 | stopListening(cm, state)
27 | if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
28 | cm.refresh()
29 | } else {
30 | state.timeout = setTimeout(check, state.delay)
31 | }
32 | }
33 | state.timeout = setTimeout(check, state.delay)
34 | state.hurry = function() {
35 | clearTimeout(state.timeout)
36 | state.timeout = setTimeout(check, 50)
37 | }
38 | CodeMirror.on(window, "mouseup", state.hurry)
39 | CodeMirror.on(window, "keyup", state.hurry)
40 | }
41 |
42 | function stopListening(_cm, state) {
43 | clearTimeout(state.timeout)
44 | CodeMirror.off(window, "mouseup", state.hurry)
45 | CodeMirror.off(window, "keyup", state.hurry)
46 | }
47 | });
48 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/fullscreen.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-fullscreen {
2 | position: fixed;
3 | top: 0; left: 0; right: 0; bottom: 0;
4 | height: auto;
5 | z-index: 9;
6 | }
7 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/fullscreen.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
15 | if (old == CodeMirror.Init) old = false;
16 | if (!old == !val) return;
17 | if (val) setFullscreen(cm);
18 | else setNormal(cm);
19 | });
20 |
21 | function setFullscreen(cm) {
22 | var wrap = cm.getWrapperElement();
23 | cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
24 | width: wrap.style.width, height: wrap.style.height};
25 | wrap.style.width = "";
26 | wrap.style.height = "auto";
27 | wrap.className += " CodeMirror-fullscreen";
28 | document.documentElement.style.overflow = "hidden";
29 | cm.refresh();
30 | }
31 |
32 | function setNormal(cm) {
33 | var wrap = cm.getWrapperElement();
34 | wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
35 | document.documentElement.style.overflow = "";
36 | var info = cm.state.fullScreenRestore;
37 | wrap.style.width = info.width; wrap.style.height = info.height;
38 | window.scrollTo(info.scrollLeft, info.scrollTop);
39 | cm.refresh();
40 | }
41 | });
42 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/panel.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function (mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function (CodeMirror) {
12 | CodeMirror.defineExtension("addPanel", function (node, options) {
13 | options = options || {};
14 |
15 | if (!this.state.panels) initPanels(this);
16 |
17 | var info = this.state.panels;
18 | var wrapper = info.wrapper;
19 | var cmWrapper = this.getWrapperElement();
20 | var replace = options.replace instanceof Panel && !options.replace.cleared;
21 |
22 | if (options.after instanceof Panel && !options.after.cleared) {
23 | wrapper.insertBefore(node, options.before.node.nextSibling);
24 | } else if (options.before instanceof Panel && !options.before.cleared) {
25 | wrapper.insertBefore(node, options.before.node);
26 | } else if (replace) {
27 | wrapper.insertBefore(node, options.replace.node);
28 | options.replace.clear(true);
29 | } else if (options.position == "bottom") {
30 | wrapper.appendChild(node);
31 | } else if (options.position == "before-bottom") {
32 | wrapper.insertBefore(node, cmWrapper.nextSibling);
33 | } else if (options.position == "after-top") {
34 | wrapper.insertBefore(node, cmWrapper);
35 | } else {
36 | wrapper.insertBefore(node, wrapper.firstChild);
37 | }
38 |
39 | var height = (options && options.height) || node.offsetHeight;
40 |
41 | var panel = new Panel(this, node, options, height);
42 | info.panels.push(panel);
43 |
44 | this.setSize();
45 | if (options.stable && isAtTop(this, node))
46 | this.scrollTo(null, this.getScrollInfo().top + height);
47 |
48 | return panel;
49 | });
50 |
51 | function Panel(cm, node, options, height) {
52 | this.cm = cm;
53 | this.node = node;
54 | this.options = options;
55 | this.height = height;
56 | this.cleared = false;
57 | }
58 |
59 | /* when skipRemove is true, clear() was called from addPanel().
60 | * Thus removePanels() should not be called (issue 5518) */
61 | Panel.prototype.clear = function (skipRemove) {
62 | if (this.cleared) return;
63 | this.cleared = true;
64 | var info = this.cm.state.panels;
65 | info.panels.splice(info.panels.indexOf(this), 1);
66 | this.cm.setSize();
67 | if (this.options.stable && isAtTop(this.cm, this.node))
68 | this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height)
69 | info.wrapper.removeChild(this.node);
70 | if (info.panels.length == 0 && !skipRemove) removePanels(this.cm);
71 | };
72 |
73 | Panel.prototype.changed = function () {
74 | this.height = this.node.getBoundingClientRect().height;
75 | this.cm.setSize();
76 | };
77 |
78 | function initPanels(cm) {
79 | var wrap = cm.getWrapperElement();
80 | var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;
81 | var height = parseInt(style.height);
82 | var info = cm.state.panels = {
83 | setHeight: wrap.style.height,
84 | panels: [],
85 | wrapper: document.createElement("div")
86 | };
87 | wrap.parentNode.insertBefore(info.wrapper, wrap);
88 | var hasFocus = cm.hasFocus();
89 | info.wrapper.appendChild(wrap);
90 | if (hasFocus) cm.focus();
91 |
92 | cm._setSize = cm.setSize;
93 | if (height != null) cm.setSize = function (width, newHeight) {
94 | if (!newHeight) newHeight = info.wrapper.offsetHeight;
95 | info.setHeight = newHeight;
96 | if (typeof newHeight != "number") {
97 | var px = /^(\d+\.?\d*)px$/.exec(newHeight);
98 | if (px) {
99 | newHeight = Number(px[1]);
100 | } else {
101 | info.wrapper.style.height = newHeight;
102 | newHeight = info.wrapper.offsetHeight;
103 | }
104 | }
105 | var editorheight = newHeight - info.panels
106 | .map(function (p) { return p.node.getBoundingClientRect().height; })
107 | .reduce(function (a, b) { return a + b; }, 0);
108 | cm._setSize(width, editorheight);
109 | height = newHeight;
110 | };
111 | }
112 |
113 | function removePanels(cm) {
114 | var info = cm.state.panels;
115 | cm.state.panels = null;
116 |
117 | var wrap = cm.getWrapperElement();
118 | info.wrapper.parentNode.replaceChild(wrap, info.wrapper);
119 | wrap.style.height = info.setHeight;
120 | cm.setSize = cm._setSize;
121 | cm.setSize();
122 | }
123 |
124 | function isAtTop(cm, dom) {
125 | for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling)
126 | if (sibling == cm.getWrapperElement()) return true
127 | return false
128 | }
129 | });
130 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/placeholder.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
13 | var prev = old && old != CodeMirror.Init;
14 | if (val && !prev) {
15 | cm.on("blur", onBlur);
16 | cm.on("change", onChange);
17 | cm.on("swapDoc", onChange);
18 | onChange(cm);
19 | } else if (!val && prev) {
20 | cm.off("blur", onBlur);
21 | cm.off("change", onChange);
22 | cm.off("swapDoc", onChange);
23 | clearPlaceholder(cm);
24 | var wrapper = cm.getWrapperElement();
25 | wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
26 | }
27 |
28 | if (val && !cm.hasFocus()) onBlur(cm);
29 | });
30 |
31 | function clearPlaceholder(cm) {
32 | if (cm.state.placeholder) {
33 | cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
34 | cm.state.placeholder = null;
35 | }
36 | }
37 | function setPlaceholder(cm) {
38 | clearPlaceholder(cm);
39 | var elt = cm.state.placeholder = document.createElement("pre");
40 | elt.style.cssText = "height: 0; overflow: visible";
41 | elt.style.direction = cm.getOption("direction");
42 | elt.className = "CodeMirror-placeholder CodeMirror-line-like";
43 | var placeHolder = cm.getOption("placeholder")
44 | if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
45 | elt.appendChild(placeHolder)
46 | cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
47 | }
48 |
49 | function onBlur(cm) {
50 | if (isEmpty(cm)) setPlaceholder(cm);
51 | }
52 | function onChange(cm) {
53 | var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
54 | wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
55 |
56 | if (empty) setPlaceholder(cm);
57 | else clearPlaceholder(cm);
58 | }
59 |
60 | function isEmpty(cm) {
61 | return (cm.lineCount() === 1) && (cm.getLine(0) === "");
62 | }
63 | });
64 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/display/rulers.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineOption("rulers", false, function(cm, val) {
15 | if (cm.state.rulerDiv) {
16 | cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv)
17 | cm.state.rulerDiv = null
18 | cm.off("refresh", drawRulers)
19 | }
20 | if (val && val.length) {
21 | cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace)
22 | cm.state.rulerDiv.className = "CodeMirror-rulers"
23 | drawRulers(cm)
24 | cm.on("refresh", drawRulers)
25 | }
26 | });
27 |
28 | function drawRulers(cm) {
29 | cm.state.rulerDiv.textContent = ""
30 | var val = cm.getOption("rulers");
31 | var cw = cm.defaultCharWidth();
32 | var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
33 | cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px";
34 | for (var i = 0; i < val.length; i++) {
35 | var elt = document.createElement("div");
36 | elt.className = "CodeMirror-ruler";
37 | var col, conf = val[i];
38 | if (typeof conf == "number") {
39 | col = conf;
40 | } else {
41 | col = conf.column;
42 | if (conf.className) elt.className += " " + conf.className;
43 | if (conf.color) elt.style.borderColor = conf.color;
44 | if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;
45 | if (conf.width) elt.style.borderLeftWidth = conf.width;
46 | }
47 | elt.style.left = (left + col * cw) + "px";
48 | cm.state.rulerDiv.appendChild(elt)
49 | }
50 | }
51 | });
52 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/edit/continuelist.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
15 | emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
16 | unorderedListRE = /[*+-]\s/;
17 |
18 | CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
19 | if (cm.getOption("disableInput")) return CodeMirror.Pass;
20 | var ranges = cm.listSelections(), replacements = [];
21 | for (var i = 0; i < ranges.length; i++) {
22 | var pos = ranges[i].head;
23 |
24 | // If we're not in Markdown mode, fall back to normal newlineAndIndent
25 | var eolState = cm.getStateAfter(pos.line);
26 | var inner = CodeMirror.innerMode(cm.getMode(), eolState);
27 | if (inner.mode.name !== "markdown") {
28 | cm.execCommand("newlineAndIndent");
29 | return;
30 | } else {
31 | eolState = inner.state;
32 | }
33 |
34 | var inList = eolState.list !== false;
35 | var inQuote = eolState.quote !== 0;
36 |
37 | var line = cm.getLine(pos.line), match = listRE.exec(line);
38 | var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch));
39 | if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) {
40 | cm.execCommand("newlineAndIndent");
41 | return;
42 | }
43 | if (emptyListRE.test(line)) {
44 | var endOfQuote = inQuote && />\s*$/.test(line)
45 | var endOfList = !/>\s*$/.test(line)
46 | if (endOfQuote || endOfList) cm.replaceRange("", {
47 | line: pos.line, ch: 0
48 | }, {
49 | line: pos.line, ch: pos.ch + 1
50 | });
51 | replacements[i] = "\n";
52 | } else {
53 | var indent = match[1], after = match[5];
54 | var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
55 | var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
56 | replacements[i] = "\n" + indent + bullet + after;
57 |
58 | if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
59 | }
60 | }
61 |
62 | cm.replaceSelections(replacements);
63 | };
64 |
65 | // Auto-updating Markdown list numbers when a new item is added to the
66 | // middle of a list
67 | function incrementRemainingMarkdownListNumbers(cm, pos) {
68 | var startLine = pos.line, lookAhead = 0, skipCount = 0;
69 | var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1];
70 |
71 | do {
72 | lookAhead += 1;
73 | var nextLineNumber = startLine + lookAhead;
74 | var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine);
75 |
76 | if (nextItem) {
77 | var nextIndent = nextItem[1];
78 | var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount);
79 | var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber;
80 |
81 | if (startIndent === nextIndent && !isNaN(nextNumber)) {
82 | if (newNumber === nextNumber) itemNumber = nextNumber + 1;
83 | if (newNumber > nextNumber) itemNumber = newNumber + 1;
84 | cm.replaceRange(
85 | nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]),
86 | {
87 | line: nextLineNumber, ch: 0
88 | }, {
89 | line: nextLineNumber, ch: nextLine.length
90 | });
91 | } else {
92 | if (startIndent.length > nextIndent.length) return;
93 | // This doesn't run if the next line immediatley indents, as it is
94 | // not clear of the users intention (new indented item or same level)
95 | if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return;
96 | skipCount += 1;
97 | }
98 | }
99 | } while (nextItem);
100 | }
101 | });
102 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/edit/matchtags.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "../fold/xml-fold"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
15 | if (old && old != CodeMirror.Init) {
16 | cm.off("cursorActivity", doMatchTags);
17 | cm.off("viewportChange", maybeUpdateMatch);
18 | clear(cm);
19 | }
20 | if (val) {
21 | cm.state.matchBothTags = typeof val == "object" && val.bothTags;
22 | cm.on("cursorActivity", doMatchTags);
23 | cm.on("viewportChange", maybeUpdateMatch);
24 | doMatchTags(cm);
25 | }
26 | });
27 |
28 | function clear(cm) {
29 | if (cm.state.tagHit) cm.state.tagHit.clear();
30 | if (cm.state.tagOther) cm.state.tagOther.clear();
31 | cm.state.tagHit = cm.state.tagOther = null;
32 | }
33 |
34 | function doMatchTags(cm) {
35 | cm.state.failedTagMatch = false;
36 | cm.operation(function() {
37 | clear(cm);
38 | if (cm.somethingSelected()) return;
39 | var cur = cm.getCursor(), range = cm.getViewport();
40 | range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
41 | var match = CodeMirror.findMatchingTag(cm, cur, range);
42 | if (!match) return;
43 | if (cm.state.matchBothTags) {
44 | var hit = match.at == "open" ? match.open : match.close;
45 | if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
46 | }
47 | var other = match.at == "close" ? match.open : match.close;
48 | if (other)
49 | cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
50 | else
51 | cm.state.failedTagMatch = true;
52 | });
53 | }
54 |
55 | function maybeUpdateMatch(cm) {
56 | if (cm.state.failedTagMatch) doMatchTags(cm);
57 | }
58 |
59 | CodeMirror.commands.toMatchingTag = function(cm) {
60 | var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
61 | if (found) {
62 | var other = found.at == "close" ? found.open : found.close;
63 | if (other) cm.extendSelection(other.to, other.from);
64 | }
65 | };
66 | });
67 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/edit/trailingspace.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
13 | if (prev == CodeMirror.Init) prev = false;
14 | if (prev && !val)
15 | cm.removeOverlay("trailingspace");
16 | else if (!prev && val)
17 | cm.addOverlay({
18 | token: function(stream) {
19 | for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
20 | if (i > stream.pos) { stream.pos = i; return null; }
21 | stream.pos = l;
22 | return "trailingspace";
23 | },
24 | name: "trailingspace"
25 | });
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/fold/brace-fold.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.registerHelper("fold", "brace", function(cm, start) {
15 | var line = start.line, lineText = cm.getLine(line);
16 | var tokenType;
17 |
18 | function findOpening(openCh) {
19 | for (var at = start.ch, pass = 0;;) {
20 | var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
21 | if (found == -1) {
22 | if (pass == 1) break;
23 | pass = 1;
24 | at = lineText.length;
25 | continue;
26 | }
27 | if (pass == 1 && found < start.ch) break;
28 | tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
29 | if (!/^(comment|string)/.test(tokenType)) return found + 1;
30 | at = found - 1;
31 | }
32 | }
33 |
34 | var startToken = "{", endToken = "}", startCh = findOpening("{");
35 | if (startCh == null) {
36 | startToken = "[", endToken = "]";
37 | startCh = findOpening("[");
38 | }
39 |
40 | if (startCh == null) return;
41 | var count = 1, lastLine = cm.lastLine(), end, endCh;
42 | outer: for (var i = line; i <= lastLine; ++i) {
43 | var text = cm.getLine(i), pos = i == line ? startCh : 0;
44 | for (;;) {
45 | var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
46 | if (nextOpen < 0) nextOpen = text.length;
47 | if (nextClose < 0) nextClose = text.length;
48 | pos = Math.min(nextOpen, nextClose);
49 | if (pos == text.length) break;
50 | if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
51 | if (pos == nextOpen) ++count;
52 | else if (!--count) { end = i; endCh = pos; break outer; }
53 | }
54 | ++pos;
55 | }
56 | }
57 | if (end == null || line == end) return;
58 | return {from: CodeMirror.Pos(line, startCh),
59 | to: CodeMirror.Pos(end, endCh)};
60 | });
61 |
62 | CodeMirror.registerHelper("fold", "import", function(cm, start) {
63 | function hasImport(line) {
64 | if (line < cm.firstLine() || line > cm.lastLine()) return null;
65 | var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
66 | if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
67 | if (start.type != "keyword" || start.string != "import") return null;
68 | // Now find closing semicolon, return its position
69 | for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
70 | var text = cm.getLine(i), semi = text.indexOf(";");
71 | if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
72 | }
73 | }
74 |
75 | var startLine = start.line, has = hasImport(startLine), prev;
76 | if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
77 | return null;
78 | for (var end = has.end;;) {
79 | var next = hasImport(end.line + 1);
80 | if (next == null) break;
81 | end = next.end;
82 | }
83 | return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
84 | });
85 |
86 | CodeMirror.registerHelper("fold", "include", function(cm, start) {
87 | function hasInclude(line) {
88 | if (line < cm.firstLine() || line > cm.lastLine()) return null;
89 | var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
90 | if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
91 | if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
92 | }
93 |
94 | var startLine = start.line, has = hasInclude(startLine);
95 | if (has == null || hasInclude(startLine - 1) != null) return null;
96 | for (var end = startLine;;) {
97 | var next = hasInclude(end + 1);
98 | if (next == null) break;
99 | ++end;
100 | }
101 | return {from: CodeMirror.Pos(startLine, has + 1),
102 | to: cm.clipPos(CodeMirror.Pos(end))};
103 | });
104 |
105 | });
106 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/fold/comment-fold.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
15 | return mode.blockCommentStart && mode.blockCommentEnd;
16 | }, function(cm, start) {
17 | var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
18 | if (!startToken || !endToken) return;
19 | var line = start.line, lineText = cm.getLine(line);
20 |
21 | var startCh;
22 | for (var at = start.ch, pass = 0;;) {
23 | var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
24 | if (found == -1) {
25 | if (pass == 1) return;
26 | pass = 1;
27 | at = lineText.length;
28 | continue;
29 | }
30 | if (pass == 1 && found < start.ch) return;
31 | if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
32 | (found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
33 | !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
34 | startCh = found + startToken.length;
35 | break;
36 | }
37 | at = found - 1;
38 | }
39 |
40 | var depth = 1, lastLine = cm.lastLine(), end, endCh;
41 | outer: for (var i = line; i <= lastLine; ++i) {
42 | var text = cm.getLine(i), pos = i == line ? startCh : 0;
43 | for (;;) {
44 | var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
45 | if (nextOpen < 0) nextOpen = text.length;
46 | if (nextClose < 0) nextClose = text.length;
47 | pos = Math.min(nextOpen, nextClose);
48 | if (pos == text.length) break;
49 | if (pos == nextOpen) ++depth;
50 | else if (!--depth) { end = i; endCh = pos; break outer; }
51 | ++pos;
52 | }
53 | }
54 | if (end == null || line == end && endCh == startCh) return;
55 | return {from: CodeMirror.Pos(line, startCh),
56 | to: CodeMirror.Pos(end, endCh)};
57 | });
58 |
59 | });
60 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/fold/foldgutter.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-foldmarker {
2 | color: blue;
3 | text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
4 | font-family: arial;
5 | line-height: .3;
6 | cursor: pointer;
7 | }
8 | .CodeMirror-foldgutter {
9 | width: .7em;
10 | }
11 | .CodeMirror-foldgutter-open,
12 | .CodeMirror-foldgutter-folded {
13 | cursor: pointer;
14 | }
15 | .CodeMirror-foldgutter-open:after {
16 | content: "\25BE";
17 | }
18 | .CodeMirror-foldgutter-folded:after {
19 | content: "\25B8";
20 | }
21 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/fold/indent-fold.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | function lineIndent(cm, lineNo) {
15 | var text = cm.getLine(lineNo)
16 | var spaceTo = text.search(/\S/)
17 | if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
18 | return -1
19 | return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
20 | }
21 |
22 | CodeMirror.registerHelper("fold", "indent", function(cm, start) {
23 | var myIndent = lineIndent(cm, start.line)
24 | if (myIndent < 0) return
25 | var lastLineInFold = null
26 |
27 | // Go through lines until we find a line that definitely doesn't belong in
28 | // the block we're folding, or to the end.
29 | for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
30 | var indent = lineIndent(cm, i)
31 | if (indent == -1) {
32 | } else if (indent > myIndent) {
33 | // Lines with a greater indent are considered part of the block.
34 | lastLineInFold = i;
35 | } else {
36 | // If this line has non-space, non-comment content, and is
37 | // indented less or equal to the start line, it is the start of
38 | // another block.
39 | break;
40 | }
41 | }
42 | if (lastLineInFold) return {
43 | from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
44 | to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
45 | };
46 | });
47 |
48 | });
49 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/fold/markdown-fold.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
15 | var maxDepth = 100;
16 |
17 | function isHeader(lineNo) {
18 | var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
19 | return tokentype && /\bheader\b/.test(tokentype);
20 | }
21 |
22 | function headerLevel(lineNo, line, nextLine) {
23 | var match = line && line.match(/^#+/);
24 | if (match && isHeader(lineNo)) return match[0].length;
25 | match = nextLine && nextLine.match(/^[=\-]+\s*$/);
26 | if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
27 | return maxDepth;
28 | }
29 |
30 | var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
31 | var level = headerLevel(start.line, firstLine, nextLine);
32 | if (level === maxDepth) return undefined;
33 |
34 | var lastLineNo = cm.lastLine();
35 | var end = start.line, nextNextLine = cm.getLine(end + 2);
36 | while (end < lastLineNo) {
37 | if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
38 | ++end;
39 | nextLine = nextNextLine;
40 | nextNextLine = cm.getLine(end + 2);
41 | }
42 |
43 | return {
44 | from: CodeMirror.Pos(start.line, firstLine.length),
45 | to: CodeMirror.Pos(end, cm.getLine(end).length)
46 | };
47 | });
48 |
49 | });
50 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/hint/anyword-hint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var WORD = /[\w$]+/, RANGE = 500;
15 |
16 | CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
17 | var word = options && options.word || WORD;
18 | var range = options && options.range || RANGE;
19 | var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
20 | var end = cur.ch, start = end;
21 | while (start && word.test(curLine.charAt(start - 1))) --start;
22 | var curWord = start != end && curLine.slice(start, end);
23 |
24 | var list = options && options.list || [], seen = {};
25 | var re = new RegExp(word.source, "g");
26 | for (var dir = -1; dir <= 1; dir += 2) {
27 | var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
28 | for (; line != endLine; line += dir) {
29 | var text = editor.getLine(line), m;
30 | while (m = re.exec(text)) {
31 | if (line == cur.line && m[0] === curWord) continue;
32 | if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
33 | seen[m[0]] = true;
34 | list.push(m[0]);
35 | }
36 | }
37 | }
38 | }
39 | return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/hint/css-hint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("../../mode/css/css"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "../../mode/css/css"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var pseudoClasses = {"active":1, "after":1, "before":1, "checked":1, "default":1,
15 | "disabled":1, "empty":1, "enabled":1, "first-child":1, "first-letter":1,
16 | "first-line":1, "first-of-type":1, "focus":1, "hover":1, "in-range":1,
17 | "indeterminate":1, "invalid":1, "lang":1, "last-child":1, "last-of-type":1,
18 | "link":1, "not":1, "nth-child":1, "nth-last-child":1, "nth-last-of-type":1,
19 | "nth-of-type":1, "only-of-type":1, "only-child":1, "optional":1, "out-of-range":1,
20 | "placeholder":1, "read-only":1, "read-write":1, "required":1, "root":1,
21 | "selection":1, "target":1, "valid":1, "visited":1
22 | };
23 |
24 | CodeMirror.registerHelper("hint", "css", function(cm) {
25 | var cur = cm.getCursor(), token = cm.getTokenAt(cur);
26 | var inner = CodeMirror.innerMode(cm.getMode(), token.state);
27 | if (inner.mode.name != "css") return;
28 |
29 | if (token.type == "keyword" && "!important".indexOf(token.string) == 0)
30 | return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start),
31 | to: CodeMirror.Pos(cur.line, token.end)};
32 |
33 | var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);
34 | if (/[^\w$_-]/.test(word)) {
35 | word = ""; start = end = cur.ch;
36 | }
37 |
38 | var spec = CodeMirror.resolveMode("text/css");
39 |
40 | var result = [];
41 | function add(keywords) {
42 | for (var name in keywords)
43 | if (!word || name.lastIndexOf(word, 0) == 0)
44 | result.push(name);
45 | }
46 |
47 | var st = inner.state.state;
48 | if (st == "pseudo" || token.type == "variable-3") {
49 | add(pseudoClasses);
50 | } else if (st == "block" || st == "maybeprop") {
51 | add(spec.propertyKeywords);
52 | } else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
53 | add(spec.valueKeywords);
54 | add(spec.colorKeywords);
55 | } else if (st == "media" || st == "media_parens") {
56 | add(spec.mediaTypes);
57 | add(spec.mediaFeatures);
58 | }
59 |
60 | if (result.length) return {
61 | list: result,
62 | from: CodeMirror.Pos(cur.line, start),
63 | to: CodeMirror.Pos(cur.line, end)
64 | };
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/hint/show-hint.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-hints {
2 | position: absolute;
3 | z-index: 10;
4 | overflow: hidden;
5 | list-style: none;
6 |
7 | margin: 0;
8 | padding: 2px;
9 |
10 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
11 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
12 | box-shadow: 2px 3px 5px rgba(0,0,0,.2);
13 | border-radius: 3px;
14 | border: 1px solid silver;
15 |
16 | background: white;
17 | font-size: 90%;
18 | font-family: monospace;
19 |
20 | max-height: 20em;
21 | overflow-y: auto;
22 | }
23 |
24 | .CodeMirror-hint {
25 | margin: 0;
26 | padding: 0 4px;
27 | border-radius: 2px;
28 | white-space: pre;
29 | color: black;
30 | cursor: pointer;
31 | }
32 |
33 | li.CodeMirror-hint-active {
34 | background: #08f;
35 | color: white;
36 | }
37 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/coffeescript-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
5 |
6 | // declare global: coffeelint
7 |
8 | (function(mod) {
9 | if (typeof exports == "object" && typeof module == "object") // CommonJS
10 | mod(require("../../lib/codemirror"));
11 | else if (typeof define == "function" && define.amd) // AMD
12 | define(["../../lib/codemirror"], mod);
13 | else // Plain browser env
14 | mod(CodeMirror);
15 | })(function(CodeMirror) {
16 | "use strict";
17 |
18 | CodeMirror.registerHelper("lint", "coffeescript", function(text) {
19 | var found = [];
20 | if (!window.coffeelint) {
21 | if (window.console) {
22 | window.console.error("Error: window.coffeelint not defined, CodeMirror CoffeeScript linting cannot run.");
23 | }
24 | return found;
25 | }
26 | var parseError = function(err) {
27 | var loc = err.lineNumber;
28 | found.push({from: CodeMirror.Pos(loc-1, 0),
29 | to: CodeMirror.Pos(loc, 0),
30 | severity: err.level,
31 | message: err.message});
32 | };
33 | try {
34 | var res = coffeelint.lint(text);
35 | for(var i = 0; i < res.length; i++) {
36 | parseError(res[i]);
37 | }
38 | } catch(e) {
39 | found.push({from: CodeMirror.Pos(e.location.first_line, 0),
40 | to: CodeMirror.Pos(e.location.last_line, e.location.last_column),
41 | severity: 'error',
42 | message: e.message});
43 | }
44 | return found;
45 | });
46 |
47 | });
48 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/css-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Depends on csslint.js from https://github.com/stubbornella/csslint
5 |
6 | // declare global: CSSLint
7 |
8 | (function(mod) {
9 | if (typeof exports == "object" && typeof module == "object") // CommonJS
10 | mod(require("../../lib/codemirror"));
11 | else if (typeof define == "function" && define.amd) // AMD
12 | define(["../../lib/codemirror"], mod);
13 | else // Plain browser env
14 | mod(CodeMirror);
15 | })(function(CodeMirror) {
16 | "use strict";
17 |
18 | CodeMirror.registerHelper("lint", "css", function(text, options) {
19 | var found = [];
20 | if (!window.CSSLint) {
21 | if (window.console) {
22 | window.console.error("Error: window.CSSLint not defined, CodeMirror CSS linting cannot run.");
23 | }
24 | return found;
25 | }
26 | var results = CSSLint.verify(text, options), messages = results.messages, message = null;
27 | for ( var i = 0; i < messages.length; i++) {
28 | message = messages[i];
29 | var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
30 | found.push({
31 | from: CodeMirror.Pos(startLine, startCol),
32 | to: CodeMirror.Pos(endLine, endCol),
33 | message: message.message,
34 | severity : message.type
35 | });
36 | }
37 | return found;
38 | });
39 |
40 | });
41 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/html-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js
5 |
6 | // declare global: HTMLHint
7 |
8 | (function(mod) {
9 | if (typeof exports == "object" && typeof module == "object") // CommonJS
10 | mod(require("../../lib/codemirror"), require("htmlhint"));
11 | else if (typeof define == "function" && define.amd) // AMD
12 | define(["../../lib/codemirror", "htmlhint"], mod);
13 | else // Plain browser env
14 | mod(CodeMirror, window.HTMLHint);
15 | })(function(CodeMirror, HTMLHint) {
16 | "use strict";
17 |
18 | var defaultRules = {
19 | "tagname-lowercase": true,
20 | "attr-lowercase": true,
21 | "attr-value-double-quotes": true,
22 | "doctype-first": false,
23 | "tag-pair": true,
24 | "spec-char-escape": true,
25 | "id-unique": true,
26 | "src-not-empty": true,
27 | "attr-no-duplication": true
28 | };
29 |
30 | CodeMirror.registerHelper("lint", "html", function(text, options) {
31 | var found = [];
32 | if (HTMLHint && !HTMLHint.verify) {
33 | if(typeof HTMLHint.default !== 'undefined') {
34 | HTMLHint = HTMLHint.default;
35 | } else {
36 | HTMLHint = HTMLHint.HTMLHint;
37 | }
38 | }
39 | if (!HTMLHint) HTMLHint = window.HTMLHint;
40 | if (!HTMLHint) {
41 | if (window.console) {
42 | window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run.");
43 | }
44 | return found;
45 | }
46 | var messages = HTMLHint.verify(text, options && options.rules || defaultRules);
47 | for (var i = 0; i < messages.length; i++) {
48 | var message = messages[i];
49 | var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col;
50 | found.push({
51 | from: CodeMirror.Pos(startLine, startCol),
52 | to: CodeMirror.Pos(endLine, endCol),
53 | message: message.message,
54 | severity : message.type
55 | });
56 | }
57 | return found;
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/javascript-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | // declare global: JSHINT
14 |
15 | function validator(text, options) {
16 | if (!window.JSHINT) {
17 | if (window.console) {
18 | window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run.");
19 | }
20 | return [];
21 | }
22 | if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation
23 | options.indent = 1; // JSHint default value is 4
24 | JSHINT(text, options, options.globals);
25 | var errors = JSHINT.data().errors, result = [];
26 | if (errors) parseErrors(errors, result);
27 | return result;
28 | }
29 |
30 | CodeMirror.registerHelper("lint", "javascript", validator);
31 |
32 | function parseErrors(errors, output) {
33 | for ( var i = 0; i < errors.length; i++) {
34 | var error = errors[i];
35 | if (error) {
36 | if (error.line <= 0) {
37 | if (window.console) {
38 | window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error);
39 | }
40 | continue;
41 | }
42 |
43 | var start = error.character - 1, end = start + 1;
44 | if (error.evidence) {
45 | var index = error.evidence.substring(start).search(/.\b/);
46 | if (index > -1) {
47 | end += index;
48 | }
49 | }
50 |
51 | // Convert to format expected by validation service
52 | var hint = {
53 | message: error.reason,
54 | severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error",
55 | from: CodeMirror.Pos(error.line - 1, start),
56 | to: CodeMirror.Pos(error.line - 1, end)
57 | };
58 |
59 | output.push(hint);
60 | }
61 | }
62 | }
63 | });
64 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/json-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Depends on jsonlint.js from https://github.com/zaach/jsonlint
5 |
6 | // declare global: jsonlint
7 |
8 | (function(mod) {
9 | if (typeof exports == "object" && typeof module == "object") // CommonJS
10 | mod(require("../../lib/codemirror"));
11 | else if (typeof define == "function" && define.amd) // AMD
12 | define(["../../lib/codemirror"], mod);
13 | else // Plain browser env
14 | mod(CodeMirror);
15 | })(function(CodeMirror) {
16 | "use strict";
17 |
18 | CodeMirror.registerHelper("lint", "json", function(text) {
19 | var found = [];
20 | if (!window.jsonlint) {
21 | if (window.console) {
22 | window.console.error("Error: window.jsonlint not defined, CodeMirror JSON linting cannot run.");
23 | }
24 | return found;
25 | }
26 | // for jsonlint's web dist jsonlint is exported as an object with a single property parser, of which parseError
27 | // is a subproperty
28 | var jsonlint = window.jsonlint.parser || window.jsonlint
29 | jsonlint.parseError = function(str, hash) {
30 | var loc = hash.loc;
31 | found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
32 | to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
33 | message: str});
34 | };
35 | try { jsonlint.parse(text); }
36 | catch(e) {}
37 | return found;
38 | });
39 |
40 | });
41 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/lint.css:
--------------------------------------------------------------------------------
1 | /* The lint marker gutter */
2 | .CodeMirror-lint-markers {
3 | width: 16px;
4 | }
5 |
6 | .CodeMirror-lint-tooltip {
7 | background-color: #ffd;
8 | border: 1px solid black;
9 | border-radius: 4px 4px 4px 4px;
10 | color: black;
11 | font-family: monospace;
12 | font-size: 10pt;
13 | overflow: hidden;
14 | padding: 2px 5px;
15 | position: fixed;
16 | white-space: pre;
17 | white-space: pre-wrap;
18 | z-index: 100;
19 | max-width: 600px;
20 | opacity: 0;
21 | transition: opacity .4s;
22 | -moz-transition: opacity .4s;
23 | -webkit-transition: opacity .4s;
24 | -o-transition: opacity .4s;
25 | -ms-transition: opacity .4s;
26 | }
27 |
28 | .CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
29 | background-position: left bottom;
30 | background-repeat: repeat-x;
31 | }
32 |
33 | .CodeMirror-lint-mark-error {
34 | background-image:
35 | url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
36 | ;
37 | }
38 |
39 | .CodeMirror-lint-mark-warning {
40 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
41 | }
42 |
43 | .CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
44 | background-position: center center;
45 | background-repeat: no-repeat;
46 | cursor: pointer;
47 | display: inline-block;
48 | height: 16px;
49 | width: 16px;
50 | vertical-align: middle;
51 | position: relative;
52 | }
53 |
54 | .CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
55 | padding-left: 18px;
56 | background-position: top left;
57 | background-repeat: no-repeat;
58 | }
59 |
60 | .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
61 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
62 | }
63 |
64 | .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
65 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
66 | }
67 |
68 | .CodeMirror-lint-marker-multiple {
69 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
70 | background-repeat: no-repeat;
71 | background-position: right bottom;
72 | width: 100%; height: 100%;
73 | }
74 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/lint/yaml-lint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | // Depends on js-yaml.js from https://github.com/nodeca/js-yaml
15 |
16 | // declare global: jsyaml
17 |
18 | CodeMirror.registerHelper("lint", "yaml", function(text) {
19 | var found = [];
20 | if (!window.jsyaml) {
21 | if (window.console) {
22 | window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run.");
23 | }
24 | return found;
25 | }
26 | try { jsyaml.loadAll(text); }
27 | catch(e) {
28 | var loc = e.mark,
29 | // js-yaml YAMLException doesn't always provide an accurate lineno
30 | // e.g., when there are multiple yaml docs
31 | // ---
32 | // ---
33 | // foo:bar
34 | from = loc ? CodeMirror.Pos(loc.line, loc.column) : CodeMirror.Pos(0, 0),
35 | to = from;
36 | found.push({ from: from, to: to, message: e.message });
37 | }
38 | return found;
39 | });
40 |
41 | });
42 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/merge/merge.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-merge {
2 | position: relative;
3 | border: 1px solid #ddd;
4 | white-space: pre;
5 | }
6 |
7 | .CodeMirror-merge, .CodeMirror-merge .CodeMirror {
8 | height: 350px;
9 | }
10 |
11 | .CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }
12 | .CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }
13 | .CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
14 | .CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
15 |
16 | .CodeMirror-merge-pane {
17 | display: inline-block;
18 | white-space: normal;
19 | vertical-align: top;
20 | }
21 | .CodeMirror-merge-pane-rightmost {
22 | position: absolute;
23 | right: 0px;
24 | z-index: 1;
25 | }
26 |
27 | .CodeMirror-merge-gap {
28 | z-index: 2;
29 | display: inline-block;
30 | height: 100%;
31 | -moz-box-sizing: border-box;
32 | box-sizing: border-box;
33 | overflow: hidden;
34 | border-left: 1px solid #ddd;
35 | border-right: 1px solid #ddd;
36 | position: relative;
37 | background: #f8f8f8;
38 | }
39 |
40 | .CodeMirror-merge-scrolllock-wrap {
41 | position: absolute;
42 | bottom: 0; left: 50%;
43 | }
44 | .CodeMirror-merge-scrolllock {
45 | position: relative;
46 | left: -50%;
47 | cursor: pointer;
48 | color: #555;
49 | line-height: 1;
50 | }
51 | .CodeMirror-merge-scrolllock:after {
52 | content: "\21db\00a0\00a0\21da";
53 | }
54 | .CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after {
55 | content: "\21db\21da";
56 | }
57 |
58 | .CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
59 | position: absolute;
60 | left: 0; top: 0;
61 | right: 0; bottom: 0;
62 | line-height: 1;
63 | }
64 |
65 | .CodeMirror-merge-copy {
66 | position: absolute;
67 | cursor: pointer;
68 | color: #44c;
69 | z-index: 3;
70 | }
71 |
72 | .CodeMirror-merge-copy-reverse {
73 | position: absolute;
74 | cursor: pointer;
75 | color: #44c;
76 | }
77 |
78 | .CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
79 | .CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
80 |
81 | .CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
82 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
83 | background-position: bottom left;
84 | background-repeat: repeat-x;
85 | }
86 |
87 | .CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
88 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
89 | background-position: bottom left;
90 | background-repeat: repeat-x;
91 | }
92 |
93 | .CodeMirror-merge-r-chunk { background: #ffffe0; }
94 | .CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }
95 | .CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }
96 | .CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }
97 |
98 | .CodeMirror-merge-l-chunk { background: #eef; }
99 | .CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
100 | .CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
101 | .CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
102 |
103 | .CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
104 | .CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
105 | .CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
106 |
107 | .CodeMirror-merge-collapsed-widget:before {
108 | content: "(...)";
109 | }
110 | .CodeMirror-merge-collapsed-widget {
111 | cursor: pointer;
112 | color: #88b;
113 | background: #eef;
114 | border: 1px solid #ddf;
115 | font-size: 90%;
116 | padding: 0 3px;
117 | border-radius: 4px;
118 | }
119 | .CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }
120 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/mode/loadmode.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), "cjs");
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); });
9 | else // Plain browser env
10 | mod(CodeMirror, "plain");
11 | })(function(CodeMirror, env) {
12 | if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
13 |
14 | var loading = {};
15 | function splitCallback(cont, n) {
16 | var countDown = n;
17 | return function() { if (--countDown == 0) cont(); };
18 | }
19 | function ensureDeps(mode, cont, options) {
20 | var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies;
21 | if (!deps) return cont();
22 | var missing = [];
23 | for (var i = 0; i < deps.length; ++i) {
24 | if (!CodeMirror.modes.hasOwnProperty(deps[i]))
25 | missing.push(deps[i]);
26 | }
27 | if (!missing.length) return cont();
28 | var split = splitCallback(cont, missing.length);
29 | for (var i = 0; i < missing.length; ++i)
30 | CodeMirror.requireMode(missing[i], split, options);
31 | }
32 |
33 | CodeMirror.requireMode = function(mode, cont, options) {
34 | if (typeof mode != "string") mode = mode.name;
35 | if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options);
36 | if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
37 |
38 | var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode);
39 | if (options && options.loadMode) {
40 | options.loadMode(file, function() { ensureDeps(mode, cont, options) })
41 | } else if (env == "plain") {
42 | var script = document.createElement("script");
43 | script.src = file;
44 | var others = document.getElementsByTagName("script")[0];
45 | var list = loading[mode] = [cont];
46 | CodeMirror.on(script, "load", function() {
47 | ensureDeps(mode, function() {
48 | for (var i = 0; i < list.length; ++i) list[i]();
49 | }, options);
50 | });
51 | others.parentNode.insertBefore(script, others);
52 | } else if (env == "cjs") {
53 | require(file);
54 | cont();
55 | } else if (env == "amd") {
56 | requirejs([file], cont);
57 | }
58 | };
59 |
60 | CodeMirror.autoLoadMode = function(instance, mode, options) {
61 | if (!CodeMirror.modes.hasOwnProperty(mode))
62 | CodeMirror.requireMode(mode, function() {
63 | instance.setOption("mode", instance.getOption("mode"));
64 | }, options);
65 | };
66 | });
67 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/mode/multiplex.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.multiplexingMode = function(outer /*, others */) {
15 | // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
16 | var others = Array.prototype.slice.call(arguments, 1);
17 |
18 | function indexOf(string, pattern, from, returnEnd) {
19 | if (typeof pattern == "string") {
20 | var found = string.indexOf(pattern, from);
21 | return returnEnd && found > -1 ? found + pattern.length : found;
22 | }
23 | var m = pattern.exec(from ? string.slice(from) : string);
24 | return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
25 | }
26 |
27 | return {
28 | startState: function() {
29 | return {
30 | outer: CodeMirror.startState(outer),
31 | innerActive: null,
32 | inner: null
33 | };
34 | },
35 |
36 | copyState: function(state) {
37 | return {
38 | outer: CodeMirror.copyState(outer, state.outer),
39 | innerActive: state.innerActive,
40 | inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
41 | };
42 | },
43 |
44 | token: function(stream, state) {
45 | if (!state.innerActive) {
46 | var cutOff = Infinity, oldContent = stream.string;
47 | for (var i = 0; i < others.length; ++i) {
48 | var other = others[i];
49 | var found = indexOf(oldContent, other.open, stream.pos);
50 | if (found == stream.pos) {
51 | if (!other.parseDelimiters) stream.match(other.open);
52 | state.innerActive = other;
53 |
54 | // Get the outer indent, making sure to handle CodeMirror.Pass
55 | var outerIndent = 0;
56 | if (outer.indent) {
57 | var possibleOuterIndent = outer.indent(state.outer, "", "");
58 | if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent;
59 | }
60 |
61 | state.inner = CodeMirror.startState(other.mode, outerIndent);
62 | return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
63 | } else if (found != -1 && found < cutOff) {
64 | cutOff = found;
65 | }
66 | }
67 | if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
68 | var outerToken = outer.token(stream, state.outer);
69 | if (cutOff != Infinity) stream.string = oldContent;
70 | return outerToken;
71 | } else {
72 | var curInner = state.innerActive, oldContent = stream.string;
73 | if (!curInner.close && stream.sol()) {
74 | state.innerActive = state.inner = null;
75 | return this.token(stream, state);
76 | }
77 | var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1;
78 | if (found == stream.pos && !curInner.parseDelimiters) {
79 | stream.match(curInner.close);
80 | state.innerActive = state.inner = null;
81 | return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close");
82 | }
83 | if (found > -1) stream.string = oldContent.slice(0, found);
84 | var innerToken = curInner.mode.token(stream, state.inner);
85 | if (found > -1) stream.string = oldContent;
86 |
87 | if (found == stream.pos && curInner.parseDelimiters)
88 | state.innerActive = state.inner = null;
89 |
90 | if (curInner.innerStyle) {
91 | if (innerToken) innerToken = innerToken + " " + curInner.innerStyle;
92 | else innerToken = curInner.innerStyle;
93 | }
94 |
95 | return innerToken;
96 | }
97 | },
98 |
99 | indent: function(state, textAfter, line) {
100 | var mode = state.innerActive ? state.innerActive.mode : outer;
101 | if (!mode.indent) return CodeMirror.Pass;
102 | return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line);
103 | },
104 |
105 | blankLine: function(state) {
106 | var mode = state.innerActive ? state.innerActive.mode : outer;
107 | if (mode.blankLine) {
108 | mode.blankLine(state.innerActive ? state.inner : state.outer);
109 | }
110 | if (!state.innerActive) {
111 | for (var i = 0; i < others.length; ++i) {
112 | var other = others[i];
113 | if (other.open === "\n") {
114 | state.innerActive = other;
115 | state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0);
116 | }
117 | }
118 | } else if (state.innerActive.close === "\n") {
119 | state.innerActive = state.inner = null;
120 | }
121 | },
122 |
123 | electricChars: outer.electricChars,
124 |
125 | innerMode: function(state) {
126 | return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
127 | }
128 | };
129 | };
130 |
131 | });
132 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/mode/multiplex_test.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function() {
5 | CodeMirror.defineMode("markdown_with_stex", function(){
6 | var inner = CodeMirror.getMode({}, "stex");
7 | var outer = CodeMirror.getMode({}, "markdown");
8 |
9 | var innerOptions = {
10 | open: '$',
11 | close: '$',
12 | mode: inner,
13 | delimStyle: 'delim',
14 | innerStyle: 'inner'
15 | };
16 |
17 | return CodeMirror.multiplexingMode(outer, innerOptions);
18 | });
19 |
20 | var mode = CodeMirror.getMode({}, "markdown_with_stex");
21 |
22 | function MT(name) {
23 | test.mode(
24 | name,
25 | mode,
26 | Array.prototype.slice.call(arguments, 1),
27 | 'multiplexing');
28 | }
29 |
30 | MT(
31 | "stexInsideMarkdown",
32 | "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]");
33 | })();
34 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/mode/overlay.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Utility function that allows modes to be combined. The mode given
5 | // as the base argument takes care of most of the normal mode
6 | // functionality, but a second (typically simple) mode is used, which
7 | // can override the style of text. Both modes get to parse all of the
8 | // text, but when both assign a non-null style to a piece of code, the
9 | // overlay wins, unless the combine argument was true and not overridden,
10 | // or state.overlay.combineTokens was true, in which case the styles are
11 | // combined.
12 |
13 | (function(mod) {
14 | if (typeof exports == "object" && typeof module == "object") // CommonJS
15 | mod(require("../../lib/codemirror"));
16 | else if (typeof define == "function" && define.amd) // AMD
17 | define(["../../lib/codemirror"], mod);
18 | else // Plain browser env
19 | mod(CodeMirror);
20 | })(function(CodeMirror) {
21 | "use strict";
22 |
23 | CodeMirror.overlayMode = function(base, overlay, combine) {
24 | return {
25 | startState: function() {
26 | return {
27 | base: CodeMirror.startState(base),
28 | overlay: CodeMirror.startState(overlay),
29 | basePos: 0, baseCur: null,
30 | overlayPos: 0, overlayCur: null,
31 | streamSeen: null
32 | };
33 | },
34 | copyState: function(state) {
35 | return {
36 | base: CodeMirror.copyState(base, state.base),
37 | overlay: CodeMirror.copyState(overlay, state.overlay),
38 | basePos: state.basePos, baseCur: null,
39 | overlayPos: state.overlayPos, overlayCur: null
40 | };
41 | },
42 |
43 | token: function(stream, state) {
44 | if (stream != state.streamSeen ||
45 | Math.min(state.basePos, state.overlayPos) < stream.start) {
46 | state.streamSeen = stream;
47 | state.basePos = state.overlayPos = stream.start;
48 | }
49 |
50 | if (stream.start == state.basePos) {
51 | state.baseCur = base.token(stream, state.base);
52 | state.basePos = stream.pos;
53 | }
54 | if (stream.start == state.overlayPos) {
55 | stream.pos = stream.start;
56 | state.overlayCur = overlay.token(stream, state.overlay);
57 | state.overlayPos = stream.pos;
58 | }
59 | stream.pos = Math.min(state.basePos, state.overlayPos);
60 |
61 | // state.overlay.combineTokens always takes precedence over combine,
62 | // unless set to null
63 | if (state.overlayCur == null) return state.baseCur;
64 | else if (state.baseCur != null &&
65 | state.overlay.combineTokens ||
66 | combine && state.overlay.combineTokens == null)
67 | return state.baseCur + " " + state.overlayCur;
68 | else return state.overlayCur;
69 | },
70 |
71 | indent: base.indent && function(state, textAfter, line) {
72 | return base.indent(state.base, textAfter, line);
73 | },
74 | electricChars: base.electricChars,
75 |
76 | innerMode: function(state) { return {state: state.base, mode: base}; },
77 |
78 | blankLine: function(state) {
79 | var baseToken, overlayToken;
80 | if (base.blankLine) baseToken = base.blankLine(state.base);
81 | if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);
82 |
83 | return overlayToken == null ?
84 | baseToken :
85 | (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken);
86 | }
87 | };
88 | };
89 |
90 | });
91 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/runmode/colorize.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("./runmode"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "./runmode"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/;
15 |
16 | function textContent(node, out) {
17 | if (node.nodeType == 3) return out.push(node.nodeValue);
18 | for (var ch = node.firstChild; ch; ch = ch.nextSibling) {
19 | textContent(ch, out);
20 | if (isBlock.test(node.nodeType)) out.push("\n");
21 | }
22 | }
23 |
24 | CodeMirror.colorize = function(collection, defaultMode) {
25 | if (!collection) collection = document.body.getElementsByTagName("pre");
26 |
27 | for (var i = 0; i < collection.length; ++i) {
28 | var node = collection[i];
29 | var mode = node.getAttribute("data-lang") || defaultMode;
30 | if (!mode) continue;
31 |
32 | var text = [];
33 | textContent(node, text);
34 | node.innerHTML = "";
35 | CodeMirror.runMode(text.join(""), mode, node);
36 |
37 | node.className += " cm-s-default";
38 | }
39 | };
40 | });
41 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/runmode/runmode.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.runMode = function(string, modespec, callback, options) {
15 | var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
16 | var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
17 |
18 | // Create a tokenizing callback function if passed-in callback is a DOM element.
19 | if (callback.appendChild) {
20 | var ie = /MSIE \d/.test(navigator.userAgent);
21 | var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
22 | var node = callback, col = 0;
23 | node.innerHTML = "";
24 | callback = function(text, style) {
25 | if (text == "\n") {
26 | // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
27 | // Emitting a carriage return makes everything ok.
28 | node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
29 | col = 0;
30 | return;
31 | }
32 | var content = "";
33 | // replace tabs
34 | for (var pos = 0;;) {
35 | var idx = text.indexOf("\t", pos);
36 | if (idx == -1) {
37 | content += text.slice(pos);
38 | col += text.length - pos;
39 | break;
40 | } else {
41 | col += idx - pos;
42 | content += text.slice(pos, idx);
43 | var size = tabSize - col % tabSize;
44 | col += size;
45 | for (var i = 0; i < size; ++i) content += " ";
46 | pos = idx + 1;
47 | }
48 | }
49 | // Create a node with token style and append it to the callback DOM element.
50 | if (style) {
51 | var sp = node.appendChild(document.createElement("span"));
52 | sp.className = "cm-" + style.replace(/ +/g, " cm-");
53 | sp.appendChild(document.createTextNode(content));
54 | } else {
55 | node.appendChild(document.createTextNode(content));
56 | }
57 | };
58 | }
59 |
60 | var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
61 | for (var i = 0, e = lines.length; i < e; ++i) {
62 | if (i) callback("\n");
63 | var stream = new CodeMirror.StringStream(lines[i], null, {
64 | lookAhead: function(n) { return lines[i + n] },
65 | baseToken: function() {}
66 | });
67 | if (!stream.string && mode.blankLine) mode.blankLine(state);
68 | while (!stream.eol()) {
69 | var style = mode.token(stream, state);
70 | callback(stream.current(), style, i, stream.start, state);
71 | stream.start = stream.pos;
72 | }
73 | }
74 | };
75 |
76 | });
77 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/scroll/annotatescrollbar.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineExtension("annotateScrollbar", function(options) {
15 | if (typeof options == "string") options = {className: options};
16 | return new Annotation(this, options);
17 | });
18 |
19 | CodeMirror.defineOption("scrollButtonHeight", 0);
20 |
21 | function Annotation(cm, options) {
22 | this.cm = cm;
23 | this.options = options;
24 | this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
25 | this.annotations = [];
26 | this.doRedraw = this.doUpdate = null;
27 | this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
28 | this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
29 | this.computeScale();
30 |
31 | function scheduleRedraw(delay) {
32 | clearTimeout(self.doRedraw);
33 | self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
34 | }
35 |
36 | var self = this;
37 | cm.on("refresh", this.resizeHandler = function() {
38 | clearTimeout(self.doUpdate);
39 | self.doUpdate = setTimeout(function() {
40 | if (self.computeScale()) scheduleRedraw(20);
41 | }, 100);
42 | });
43 | cm.on("markerAdded", this.resizeHandler);
44 | cm.on("markerCleared", this.resizeHandler);
45 | if (options.listenForChanges !== false)
46 | cm.on("changes", this.changeHandler = function() {
47 | scheduleRedraw(250);
48 | });
49 | }
50 |
51 | Annotation.prototype.computeScale = function() {
52 | var cm = this.cm;
53 | var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
54 | cm.getScrollerElement().scrollHeight
55 | if (hScale != this.hScale) {
56 | this.hScale = hScale;
57 | return true;
58 | }
59 | };
60 |
61 | Annotation.prototype.update = function(annotations) {
62 | this.annotations = annotations;
63 | this.redraw();
64 | };
65 |
66 | Annotation.prototype.redraw = function(compute) {
67 | if (compute !== false) this.computeScale();
68 | var cm = this.cm, hScale = this.hScale;
69 |
70 | var frag = document.createDocumentFragment(), anns = this.annotations;
71 |
72 | var wrapping = cm.getOption("lineWrapping");
73 | var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
74 | var curLine = null, curLineObj = null;
75 | function getY(pos, top) {
76 | if (curLine != pos.line) {
77 | curLine = pos.line;
78 | curLineObj = cm.getLineHandle(curLine);
79 | }
80 | if ((curLineObj.widgets && curLineObj.widgets.length) ||
81 | (wrapping && curLineObj.height > singleLineH))
82 | return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
83 | var topY = cm.heightAtLine(curLineObj, "local");
84 | return topY + (top ? 0 : curLineObj.height);
85 | }
86 |
87 | var lastLine = cm.lastLine()
88 | if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
89 | var ann = anns[i];
90 | if (ann.to.line > lastLine) continue;
91 | var top = nextTop || getY(ann.from, true) * hScale;
92 | var bottom = getY(ann.to, false) * hScale;
93 | while (i < anns.length - 1) {
94 | if (anns[i + 1].to.line > lastLine) break;
95 | nextTop = getY(anns[i + 1].from, true) * hScale;
96 | if (nextTop > bottom + .9) break;
97 | ann = anns[++i];
98 | bottom = getY(ann.to, false) * hScale;
99 | }
100 | if (bottom == top) continue;
101 | var height = Math.max(bottom - top, 3);
102 |
103 | var elt = frag.appendChild(document.createElement("div"));
104 | elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
105 | + (top + this.buttonHeight) + "px; height: " + height + "px";
106 | elt.className = this.options.className;
107 | if (ann.id) {
108 | elt.setAttribute("annotation-id", ann.id);
109 | }
110 | }
111 | this.div.textContent = "";
112 | this.div.appendChild(frag);
113 | };
114 |
115 | Annotation.prototype.clear = function() {
116 | this.cm.off("refresh", this.resizeHandler);
117 | this.cm.off("markerAdded", this.resizeHandler);
118 | this.cm.off("markerCleared", this.resizeHandler);
119 | if (this.changeHandler) this.cm.off("changes", this.changeHandler);
120 | this.div.parentNode.removeChild(this.div);
121 | };
122 | });
123 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/scroll/scrollpastend.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
15 | if (old && old != CodeMirror.Init) {
16 | cm.off("change", onChange);
17 | cm.off("refresh", updateBottomMargin);
18 | cm.display.lineSpace.parentNode.style.paddingBottom = "";
19 | cm.state.scrollPastEndPadding = null;
20 | }
21 | if (val) {
22 | cm.on("change", onChange);
23 | cm.on("refresh", updateBottomMargin);
24 | updateBottomMargin(cm);
25 | }
26 | });
27 |
28 | function onChange(cm, change) {
29 | if (CodeMirror.changeEnd(change).line == cm.lastLine())
30 | updateBottomMargin(cm);
31 | }
32 |
33 | function updateBottomMargin(cm) {
34 | var padding = "";
35 | if (cm.lineCount() > 1) {
36 | var totalH = cm.display.scroller.clientHeight - 30,
37 | lastLineH = cm.getLineHandle(cm.lastLine()).height;
38 | padding = (totalH - lastLineH) + "px";
39 | }
40 | if (cm.state.scrollPastEndPadding != padding) {
41 | cm.state.scrollPastEndPadding = padding;
42 | cm.display.lineSpace.parentNode.style.paddingBottom = padding;
43 | cm.off("refresh", updateBottomMargin);
44 | cm.setSize();
45 | cm.on("refresh", updateBottomMargin);
46 | }
47 | }
48 | });
49 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/scroll/simplescrollbars.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div {
2 | position: absolute;
3 | background: #ccc;
4 | -moz-box-sizing: border-box;
5 | box-sizing: border-box;
6 | border: 1px solid #bbb;
7 | border-radius: 2px;
8 | }
9 |
10 | .CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical {
11 | position: absolute;
12 | z-index: 6;
13 | background: #eee;
14 | }
15 |
16 | .CodeMirror-simplescroll-horizontal {
17 | bottom: 0; left: 0;
18 | height: 8px;
19 | }
20 | .CodeMirror-simplescroll-horizontal div {
21 | bottom: 0;
22 | height: 100%;
23 | }
24 |
25 | .CodeMirror-simplescroll-vertical {
26 | right: 0; top: 0;
27 | width: 8px;
28 | }
29 | .CodeMirror-simplescroll-vertical div {
30 | right: 0;
31 | width: 100%;
32 | }
33 |
34 |
35 | .CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler {
36 | display: none;
37 | }
38 |
39 | .CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
40 | position: absolute;
41 | background: #bcd;
42 | border-radius: 3px;
43 | }
44 |
45 | .CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {
46 | position: absolute;
47 | z-index: 6;
48 | }
49 |
50 | .CodeMirror-overlayscroll-horizontal {
51 | bottom: 0; left: 0;
52 | height: 6px;
53 | }
54 | .CodeMirror-overlayscroll-horizontal div {
55 | bottom: 0;
56 | height: 100%;
57 | }
58 |
59 | .CodeMirror-overlayscroll-vertical {
60 | right: 0; top: 0;
61 | width: 6px;
62 | }
63 | .CodeMirror-overlayscroll-vertical div {
64 | right: 0;
65 | width: 100%;
66 | }
67 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/search/jump-to-line.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Defines jumpToLine command. Uses dialog.js if present.
5 |
6 | (function(mod) {
7 | if (typeof exports == "object" && typeof module == "object") // CommonJS
8 | mod(require("../../lib/codemirror"), require("../dialog/dialog"));
9 | else if (typeof define == "function" && define.amd) // AMD
10 | define(["../../lib/codemirror", "../dialog/dialog"], mod);
11 | else // Plain browser env
12 | mod(CodeMirror);
13 | })(function(CodeMirror) {
14 | "use strict";
15 |
16 | function dialog(cm, text, shortText, deflt, f) {
17 | if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
18 | else f(prompt(shortText, deflt));
19 | }
20 |
21 | function getJumpDialog(cm) {
22 | return cm.phrase("Jump to line:") + ' ' + cm.phrase("(Use line:column or scroll% syntax)") + ' ';
23 | }
24 |
25 | function interpretLine(cm, string) {
26 | var num = Number(string)
27 | if (/^[-+]/.test(string)) return cm.getCursor().line + num
28 | else return num - 1
29 | }
30 |
31 | CodeMirror.commands.jumpToLine = function(cm) {
32 | var cur = cm.getCursor();
33 | dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) {
34 | if (!posStr) return;
35 |
36 | var match;
37 | if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
38 | cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
39 | } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
40 | var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
41 | if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
42 | cm.setCursor(line - 1, cur.ch);
43 | } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
44 | cm.setCursor(interpretLine(cm, match[1]), cur.ch);
45 | }
46 | });
47 | };
48 |
49 | CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
50 | });
51 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/search/matchesonscrollbar.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-search-match {
2 | background: gold;
3 | border-top: 1px solid orange;
4 | border-bottom: 1px solid orange;
5 | -moz-box-sizing: border-box;
6 | box-sizing: border-box;
7 | opacity: .5;
8 | }
9 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/search/matchesonscrollbar.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
15 | if (typeof options == "string") options = {className: options};
16 | if (!options) options = {};
17 | return new SearchAnnotation(this, query, caseFold, options);
18 | });
19 |
20 | function SearchAnnotation(cm, query, caseFold, options) {
21 | this.cm = cm;
22 | this.options = options;
23 | var annotateOptions = {listenForChanges: false};
24 | for (var prop in options) annotateOptions[prop] = options[prop];
25 | if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
26 | this.annotation = cm.annotateScrollbar(annotateOptions);
27 | this.query = query;
28 | this.caseFold = caseFold;
29 | this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
30 | this.matches = [];
31 | this.update = null;
32 |
33 | this.findMatches();
34 | this.annotation.update(this.matches);
35 |
36 | var self = this;
37 | cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
38 | }
39 |
40 | var MAX_MATCHES = 1000;
41 |
42 | SearchAnnotation.prototype.findMatches = function() {
43 | if (!this.gap) return;
44 | for (var i = 0; i < this.matches.length; i++) {
45 | var match = this.matches[i];
46 | if (match.from.line >= this.gap.to) break;
47 | if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
48 | }
49 | var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline});
50 | var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
51 | while (cursor.findNext()) {
52 | var match = {from: cursor.from(), to: cursor.to()};
53 | if (match.from.line >= this.gap.to) break;
54 | this.matches.splice(i++, 0, match);
55 | if (this.matches.length > maxMatches) break;
56 | }
57 | this.gap = null;
58 | };
59 |
60 | function offsetLine(line, changeStart, sizeChange) {
61 | if (line <= changeStart) return line;
62 | return Math.max(changeStart, line + sizeChange);
63 | }
64 |
65 | SearchAnnotation.prototype.onChange = function(change) {
66 | var startLine = change.from.line;
67 | var endLine = CodeMirror.changeEnd(change).line;
68 | var sizeChange = endLine - change.to.line;
69 | if (this.gap) {
70 | this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
71 | this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
72 | } else {
73 | this.gap = {from: change.from.line, to: endLine + 1};
74 | }
75 |
76 | if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
77 | var match = this.matches[i];
78 | var newFrom = offsetLine(match.from.line, startLine, sizeChange);
79 | if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
80 | var newTo = offsetLine(match.to.line, startLine, sizeChange);
81 | if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
82 | }
83 | clearTimeout(this.update);
84 | var self = this;
85 | this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
86 | };
87 |
88 | SearchAnnotation.prototype.updateAfterChange = function() {
89 | this.findMatches();
90 | this.annotation.update(this.matches);
91 | };
92 |
93 | SearchAnnotation.prototype.clear = function() {
94 | this.cm.off("change", this.changeHandler);
95 | this.annotation.clear();
96 | };
97 | });
98 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/selection/active-line.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | var WRAP_CLASS = "CodeMirror-activeline";
14 | var BACK_CLASS = "CodeMirror-activeline-background";
15 | var GUTT_CLASS = "CodeMirror-activeline-gutter";
16 |
17 | CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
18 | var prev = old == CodeMirror.Init ? false : old;
19 | if (val == prev) return
20 | if (prev) {
21 | cm.off("beforeSelectionChange", selectionChange);
22 | clearActiveLines(cm);
23 | delete cm.state.activeLines;
24 | }
25 | if (val) {
26 | cm.state.activeLines = [];
27 | updateActiveLines(cm, cm.listSelections());
28 | cm.on("beforeSelectionChange", selectionChange);
29 | }
30 | });
31 |
32 | function clearActiveLines(cm) {
33 | for (var i = 0; i < cm.state.activeLines.length; i++) {
34 | cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
35 | cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
36 | cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS);
37 | }
38 | }
39 |
40 | function sameArray(a, b) {
41 | if (a.length != b.length) return false;
42 | for (var i = 0; i < a.length; i++)
43 | if (a[i] != b[i]) return false;
44 | return true;
45 | }
46 |
47 | function updateActiveLines(cm, ranges) {
48 | var active = [];
49 | for (var i = 0; i < ranges.length; i++) {
50 | var range = ranges[i];
51 | var option = cm.getOption("styleActiveLine");
52 | if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty())
53 | continue
54 | var line = cm.getLineHandleVisualStart(range.head.line);
55 | if (active[active.length - 1] != line) active.push(line);
56 | }
57 | if (sameArray(cm.state.activeLines, active)) return;
58 | cm.operation(function() {
59 | clearActiveLines(cm);
60 | for (var i = 0; i < active.length; i++) {
61 | cm.addLineClass(active[i], "wrap", WRAP_CLASS);
62 | cm.addLineClass(active[i], "background", BACK_CLASS);
63 | cm.addLineClass(active[i], "gutter", GUTT_CLASS);
64 | }
65 | cm.state.activeLines = active;
66 | });
67 | }
68 |
69 | function selectionChange(cm, sel) {
70 | updateActiveLines(cm, sel.ranges);
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/selection/mark-selection.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // Because sometimes you need to mark the selected *text*.
5 | //
6 | // Adds an option 'styleSelectedText' which, when enabled, gives
7 | // selected text the CSS class given as option value, or
8 | // "CodeMirror-selectedtext" when the value is not a string.
9 |
10 | (function(mod) {
11 | if (typeof exports == "object" && typeof module == "object") // CommonJS
12 | mod(require("../../lib/codemirror"));
13 | else if (typeof define == "function" && define.amd) // AMD
14 | define(["../../lib/codemirror"], mod);
15 | else // Plain browser env
16 | mod(CodeMirror);
17 | })(function(CodeMirror) {
18 | "use strict";
19 |
20 | CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
21 | var prev = old && old != CodeMirror.Init;
22 | if (val && !prev) {
23 | cm.state.markedSelection = [];
24 | cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
25 | reset(cm);
26 | cm.on("cursorActivity", onCursorActivity);
27 | cm.on("change", onChange);
28 | } else if (!val && prev) {
29 | cm.off("cursorActivity", onCursorActivity);
30 | cm.off("change", onChange);
31 | clear(cm);
32 | cm.state.markedSelection = cm.state.markedSelectionStyle = null;
33 | }
34 | });
35 |
36 | function onCursorActivity(cm) {
37 | if (cm.state.markedSelection)
38 | cm.operation(function() { update(cm); });
39 | }
40 |
41 | function onChange(cm) {
42 | if (cm.state.markedSelection && cm.state.markedSelection.length)
43 | cm.operation(function() { clear(cm); });
44 | }
45 |
46 | var CHUNK_SIZE = 8;
47 | var Pos = CodeMirror.Pos;
48 | var cmp = CodeMirror.cmpPos;
49 |
50 | function coverRange(cm, from, to, addAt) {
51 | if (cmp(from, to) == 0) return;
52 | var array = cm.state.markedSelection;
53 | var cls = cm.state.markedSelectionStyle;
54 | for (var line = from.line;;) {
55 | var start = line == from.line ? from : Pos(line, 0);
56 | var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
57 | var end = atEnd ? to : Pos(endLine, 0);
58 | var mark = cm.markText(start, end, {className: cls});
59 | if (addAt == null) array.push(mark);
60 | else array.splice(addAt++, 0, mark);
61 | if (atEnd) break;
62 | line = endLine;
63 | }
64 | }
65 |
66 | function clear(cm) {
67 | var array = cm.state.markedSelection;
68 | for (var i = 0; i < array.length; ++i) array[i].clear();
69 | array.length = 0;
70 | }
71 |
72 | function reset(cm) {
73 | clear(cm);
74 | var ranges = cm.listSelections();
75 | for (var i = 0; i < ranges.length; i++)
76 | coverRange(cm, ranges[i].from(), ranges[i].to());
77 | }
78 |
79 | function update(cm) {
80 | if (!cm.somethingSelected()) return clear(cm);
81 | if (cm.listSelections().length > 1) return reset(cm);
82 |
83 | var from = cm.getCursor("start"), to = cm.getCursor("end");
84 |
85 | var array = cm.state.markedSelection;
86 | if (!array.length) return coverRange(cm, from, to);
87 |
88 | var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
89 | if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE ||
90 | cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
91 | return reset(cm);
92 |
93 | while (cmp(from, coverStart.from) > 0) {
94 | array.shift().clear();
95 | coverStart = array[0].find();
96 | }
97 | if (cmp(from, coverStart.from) < 0) {
98 | if (coverStart.to.line - from.line < CHUNK_SIZE) {
99 | array.shift().clear();
100 | coverRange(cm, from, coverStart.to, 0);
101 | } else {
102 | coverRange(cm, from, coverStart.from, 0);
103 | }
104 | }
105 |
106 | while (cmp(to, coverEnd.to) < 0) {
107 | array.pop().clear();
108 | coverEnd = array[array.length - 1].find();
109 | }
110 | if (cmp(to, coverEnd.to) > 0) {
111 | if (to.line - coverEnd.from.line < CHUNK_SIZE) {
112 | array.pop().clear();
113 | coverRange(cm, coverEnd.from, to);
114 | } else {
115 | coverRange(cm, coverEnd.to, to);
116 | }
117 | }
118 | }
119 | });
120 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/selection/selection-pointer.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineOption("selectionPointer", false, function(cm, val) {
15 | var data = cm.state.selectionPointer;
16 | if (data) {
17 | CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove);
18 | CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout);
19 | CodeMirror.off(window, "scroll", data.windowScroll);
20 | cm.off("cursorActivity", reset);
21 | cm.off("scroll", reset);
22 | cm.state.selectionPointer = null;
23 | cm.display.lineDiv.style.cursor = "";
24 | }
25 | if (val) {
26 | data = cm.state.selectionPointer = {
27 | value: typeof val == "string" ? val : "default",
28 | mousemove: function(event) { mousemove(cm, event); },
29 | mouseout: function(event) { mouseout(cm, event); },
30 | windowScroll: function() { reset(cm); },
31 | rects: null,
32 | mouseX: null, mouseY: null,
33 | willUpdate: false
34 | };
35 | CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove);
36 | CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout);
37 | CodeMirror.on(window, "scroll", data.windowScroll);
38 | cm.on("cursorActivity", reset);
39 | cm.on("scroll", reset);
40 | }
41 | });
42 |
43 | function mousemove(cm, event) {
44 | var data = cm.state.selectionPointer;
45 | if (event.buttons == null ? event.which : event.buttons) {
46 | data.mouseX = data.mouseY = null;
47 | } else {
48 | data.mouseX = event.clientX;
49 | data.mouseY = event.clientY;
50 | }
51 | scheduleUpdate(cm);
52 | }
53 |
54 | function mouseout(cm, event) {
55 | if (!cm.getWrapperElement().contains(event.relatedTarget)) {
56 | var data = cm.state.selectionPointer;
57 | data.mouseX = data.mouseY = null;
58 | scheduleUpdate(cm);
59 | }
60 | }
61 |
62 | function reset(cm) {
63 | cm.state.selectionPointer.rects = null;
64 | scheduleUpdate(cm);
65 | }
66 |
67 | function scheduleUpdate(cm) {
68 | if (!cm.state.selectionPointer.willUpdate) {
69 | cm.state.selectionPointer.willUpdate = true;
70 | setTimeout(function() {
71 | update(cm);
72 | cm.state.selectionPointer.willUpdate = false;
73 | }, 50);
74 | }
75 | }
76 |
77 | function update(cm) {
78 | var data = cm.state.selectionPointer;
79 | if (!data) return;
80 | if (data.rects == null && data.mouseX != null) {
81 | data.rects = [];
82 | if (cm.somethingSelected()) {
83 | for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling)
84 | data.rects.push(sel.getBoundingClientRect());
85 | }
86 | }
87 | var inside = false;
88 | if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) {
89 | var rect = data.rects[i];
90 | if (rect.left <= data.mouseX && rect.right >= data.mouseX &&
91 | rect.top <= data.mouseY && rect.bottom >= data.mouseY)
92 | inside = true;
93 | }
94 | var cursor = inside ? data.value : "";
95 | if (cm.display.lineDiv.style.cursor != cursor)
96 | cm.display.lineDiv.style.cursor = cursor;
97 | }
98 | });
99 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/tern/tern.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-Tern-completion {
2 | padding-left: 22px;
3 | position: relative;
4 | line-height: 1.5;
5 | }
6 | .CodeMirror-Tern-completion:before {
7 | position: absolute;
8 | left: 2px;
9 | bottom: 2px;
10 | border-radius: 50%;
11 | font-size: 12px;
12 | font-weight: bold;
13 | height: 15px;
14 | width: 15px;
15 | line-height: 16px;
16 | text-align: center;
17 | color: white;
18 | -moz-box-sizing: border-box;
19 | box-sizing: border-box;
20 | }
21 | .CodeMirror-Tern-completion-unknown:before {
22 | content: "?";
23 | background: #4bb;
24 | }
25 | .CodeMirror-Tern-completion-object:before {
26 | content: "O";
27 | background: #77c;
28 | }
29 | .CodeMirror-Tern-completion-fn:before {
30 | content: "F";
31 | background: #7c7;
32 | }
33 | .CodeMirror-Tern-completion-array:before {
34 | content: "A";
35 | background: #c66;
36 | }
37 | .CodeMirror-Tern-completion-number:before {
38 | content: "1";
39 | background: #999;
40 | }
41 | .CodeMirror-Tern-completion-string:before {
42 | content: "S";
43 | background: #999;
44 | }
45 | .CodeMirror-Tern-completion-bool:before {
46 | content: "B";
47 | background: #999;
48 | }
49 |
50 | .CodeMirror-Tern-completion-guess {
51 | color: #999;
52 | }
53 |
54 | .CodeMirror-Tern-tooltip {
55 | border: 1px solid silver;
56 | border-radius: 3px;
57 | color: #444;
58 | padding: 2px 5px;
59 | font-size: 90%;
60 | font-family: monospace;
61 | background-color: white;
62 | white-space: pre-wrap;
63 |
64 | max-width: 40em;
65 | position: absolute;
66 | z-index: 10;
67 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
68 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
69 | box-shadow: 2px 3px 5px rgba(0,0,0,.2);
70 |
71 | transition: opacity 1s;
72 | -moz-transition: opacity 1s;
73 | -webkit-transition: opacity 1s;
74 | -o-transition: opacity 1s;
75 | -ms-transition: opacity 1s;
76 | }
77 |
78 | .CodeMirror-Tern-hint-doc {
79 | max-width: 25em;
80 | margin-top: -3px;
81 | }
82 |
83 | .CodeMirror-Tern-fname { color: black; }
84 | .CodeMirror-Tern-farg { color: #70a; }
85 | .CodeMirror-Tern-farg-current { text-decoration: underline; }
86 | .CodeMirror-Tern-type { color: #07c; }
87 | .CodeMirror-Tern-fhint-guess { opacity: .7; }
88 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/addon/tern/worker.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | // declare global: tern, server
5 |
6 | var server;
7 |
8 | this.onmessage = function(e) {
9 | var data = e.data;
10 | switch (data.type) {
11 | case "init": return startServer(data.defs, data.plugins, data.scripts);
12 | case "add": return server.addFile(data.name, data.text);
13 | case "del": return server.delFile(data.name);
14 | case "req": return server.request(data.body, function(err, reqData) {
15 | postMessage({id: data.id, body: reqData, err: err && String(err)});
16 | });
17 | case "getFile":
18 | var c = pending[data.id];
19 | delete pending[data.id];
20 | return c(data.err, data.text);
21 | default: throw new Error("Unknown message type: " + data.type);
22 | }
23 | };
24 |
25 | var nextId = 0, pending = {};
26 | function getFile(file, c) {
27 | postMessage({type: "getFile", name: file, id: ++nextId});
28 | pending[nextId] = c;
29 | }
30 |
31 | function startServer(defs, plugins, scripts) {
32 | if (scripts) importScripts.apply(null, scripts);
33 |
34 | server = new tern.Server({
35 | getFile: getFile,
36 | async: true,
37 | defs: defs,
38 | plugins: plugins
39 | });
40 | }
41 |
42 | this.console = {
43 | log: function(v) { postMessage({type: "debug", message: v}); }
44 | };
45 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/mode/javascript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | CodeMirror: JavaScript mode
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
27 |
28 |
29 | JavaScript mode
30 |
31 |
32 |
81 |
82 |
90 |
91 |
92 | JavaScript mode supports several configuration options:
93 |
94 | json
which will set the mode to expect JSON
95 | data rather than a JavaScript program.
96 | jsonld
which will set the mode to expect
97 | JSON-LD linked data rather
98 | than a JavaScript program (demo ).
99 | typescript
which will activate additional
100 | syntax highlighting and some other things for TypeScript code
101 | (demo ).
102 | statementIndent
which (given a number) will
103 | determine the amount of indentation to use for statements
104 | continued on a new line.
105 | wordCharacters
, a regexp that indicates which
106 | characters should be considered part of an identifier.
107 | Defaults to /[\w$]/
, which does not handle
108 | non-ASCII identifiers. Can be set to something more elaborate
109 | to improve Unicode support.
110 |
111 |
112 |
113 | MIME types defined: text/javascript
, application/json
, application/ld+json
, text/typescript
, application/typescript
.
114 |
115 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/mode/javascript/json-ld.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | CodeMirror: JSON-LD mode
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
27 |
28 |
29 | JSON-LD mode
30 |
31 |
32 |
61 |
62 |
70 |
71 | This is a specialization of the JavaScript mode .
72 |
73 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/mode/javascript/typescript.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | CodeMirror: TypeScript mode
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
25 |
26 |
27 | TypeScript mode
28 |
29 |
30 |
52 |
53 |
60 |
61 | This is a specialization of the JavaScript mode .
62 |
63 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/theme/darcula.css:
--------------------------------------------------------------------------------
1 | /**
2 | Name: IntelliJ IDEA darcula theme
3 | From IntelliJ IDEA by JetBrains
4 | */
5 |
6 | .cm-s-darcula { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;}
7 | .cm-s-darcula.CodeMirror { background: #2B2B2B; color: #A9B7C6; }
8 |
9 | .cm-s-darcula span.cm-meta { color: #BBB529; }
10 | .cm-s-darcula span.cm-number { color: #6897BB; }
11 | .cm-s-darcula span.cm-keyword { color: #CC7832; line-height: 1em; font-weight: bold; }
12 | .cm-s-darcula span.cm-def { color: #A9B7C6; font-style: italic; }
13 | .cm-s-darcula span.cm-variable { color: #A9B7C6; }
14 | .cm-s-darcula span.cm-variable-2 { color: #A9B7C6; }
15 | .cm-s-darcula span.cm-variable-3 { color: #9876AA; }
16 | .cm-s-darcula span.cm-type { color: #AABBCC; font-weight: bold; }
17 | .cm-s-darcula span.cm-property { color: #FFC66D; }
18 | .cm-s-darcula span.cm-operator { color: #A9B7C6; }
19 | .cm-s-darcula span.cm-string { color: #6A8759; }
20 | .cm-s-darcula span.cm-string-2 { color: #6A8759; }
21 | .cm-s-darcula span.cm-comment { color: #61A151; font-style: italic; }
22 | .cm-s-darcula span.cm-link { color: #CC7832; }
23 | .cm-s-darcula span.cm-atom { color: #CC7832; }
24 | .cm-s-darcula span.cm-error { color: #BC3F3C; }
25 | .cm-s-darcula span.cm-tag { color: #629755; font-weight: bold; font-style: italic; text-decoration: underline; }
26 | .cm-s-darcula span.cm-attribute { color: #6897bb; }
27 | .cm-s-darcula span.cm-qualifier { color: #6A8759; }
28 | .cm-s-darcula span.cm-bracket { color: #A9B7C6; }
29 | .cm-s-darcula span.cm-builtin { color: #FF9E59; }
30 | .cm-s-darcula span.cm-special { color: #FF9E59; }
31 | .cm-s-darcula span.cm-matchhighlight { color: #FFFFFF; background-color: rgba(50, 89, 48, .7); font-weight: normal;}
32 | .cm-s-darcula span.cm-searching { color: #FFFFFF; background-color: rgba(61, 115, 59, .7); font-weight: normal;}
33 |
34 | .cm-s-darcula .CodeMirror-cursor { border-left: 1px solid #A9B7C6; }
35 | .cm-s-darcula .CodeMirror-activeline-background { background: #323232; }
36 | .cm-s-darcula .CodeMirror-gutters { background: #313335; border-right: 1px solid #313335; }
37 | .cm-s-darcula .CodeMirror-guttermarker { color: #FFEE80; }
38 | .cm-s-darcula .CodeMirror-guttermarker-subtle { color: #D0D0D0; }
39 | .cm-s-darcula .CodeMirrir-linenumber { color: #606366; }
40 | .cm-s-darcula .CodeMirror-matchingbracket { background-color: #3B514D; color: #FFEF28 !important; font-weight: bold; }
41 |
42 | .cm-s-darcula div.CodeMirror-selected { background: #214283; }
43 |
44 | .CodeMirror-hints.darcula {
45 | font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
46 | color: #9C9E9E;
47 | background-color: #3B3E3F !important;
48 | }
49 |
50 | .CodeMirror-hints.darcula .CodeMirror-hint-active {
51 | background-color: #494D4E !important;
52 | color: #9C9E9E !important;
53 | }
54 |
--------------------------------------------------------------------------------
/play/src/main/assets/web/theme/monokai.css:
--------------------------------------------------------------------------------
1 | /* Based on Sublime Text's Monokai theme */
2 |
3 | .cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }
4 | .cm-s-monokai div.CodeMirror-selected { background: #49483E; }
5 | .cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }
6 | .cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }
7 | .cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }
8 | .cm-s-monokai .CodeMirror-guttermarker { color: white; }
9 | .cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
10 | .cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }
11 | .cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
12 |
13 | .cm-s-monokai span.cm-comment { color: #75715e; }
14 | .cm-s-monokai span.cm-atom { color: #ae81ff; }
15 | .cm-s-monokai span.cm-number { color: #ae81ff; }
16 |
17 | .cm-s-monokai span.cm-comment.cm-attribute { color: #97b757; }
18 | .cm-s-monokai span.cm-comment.cm-def { color: #bc9262; }
19 | .cm-s-monokai span.cm-comment.cm-tag { color: #bc6283; }
20 | .cm-s-monokai span.cm-comment.cm-type { color: #5998a6; }
21 |
22 | .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }
23 | .cm-s-monokai span.cm-keyword { color: #f92672; }
24 | .cm-s-monokai span.cm-builtin { color: #66d9ef; }
25 | .cm-s-monokai span.cm-string { color: #e6db74; }
26 |
27 | .cm-s-monokai span.cm-variable { color: #f8f8f2; }
28 | .cm-s-monokai span.cm-variable-2 { color: #9effff; }
29 | .cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }
30 | .cm-s-monokai span.cm-def { color: #fd971f; }
31 | .cm-s-monokai span.cm-bracket { color: #f8f8f2; }
32 | .cm-s-monokai span.cm-tag { color: #f92672; }
33 | .cm-s-monokai span.cm-header { color: #ae81ff; }
34 | .cm-s-monokai span.cm-link { color: #ae81ff; }
35 | .cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }
36 |
37 | .cm-s-monokai .CodeMirror-activeline-background { background: #373831; }
38 | .cm-s-monokai .CodeMirror-matchingbracket {
39 | text-decoration: underline;
40 | color: white !important;
41 | }
42 |
--------------------------------------------------------------------------------
/play/src/main/java/github/hotstu/lu/play/Function.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.play;
2 |
3 | /**
4 | * @author hglf [hglf](https://github.com/hotstu)
5 | * @desc
6 | * @since 9/18/20
7 | */
8 | public interface Function {
9 | R apply(T input);
10 | }
11 |
--------------------------------------------------------------------------------
/play/src/main/java/github/hotstu/lu/play/HttpDaemonService.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.play;
2 |
3 | import android.app.NotificationChannel;
4 | import android.app.NotificationManager;
5 | import android.app.Service;
6 | import android.content.Intent;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.os.IBinder;
10 | import android.os.RemoteException;
11 |
12 | import androidx.annotation.Nullable;
13 | import androidx.core.app.NotificationCompat;
14 |
15 | import com.google.gson.Gson;
16 |
17 | import java.util.HashMap;
18 |
19 | import github.hotstu.lu.base.IPlayCallback;
20 | import github.hotstu.lu.base.IPlayService;
21 |
22 | /**
23 | * @author hglf [hglf](https://github.com/hotstu)
24 | * @desc
25 | * @since 7/15/20
26 | */
27 | public class HttpDaemonService extends Service {
28 |
29 | class MyBinder extends IPlayService.Stub {
30 | private final Object accessLock = new Object();
31 | private IPlayCallback callback = null;
32 |
33 |
34 | public IPlayCallback getCallback() {
35 | return callback;
36 | }
37 |
38 | @Override
39 | public void setCallback(final IPlayCallback callback) {
40 | synchronized (accessLock) {
41 | this.callback = callback;
42 | updateState();
43 | }
44 |
45 | }
46 |
47 |
48 |
49 | private void updateState() {
50 |
51 | boolean empty = callback == null;
52 |
53 | if (empty) {
54 | stopServer();
55 | } else {
56 | startServer();
57 | }
58 |
59 | }
60 |
61 | }
62 |
63 | MyBinder mBinder = null;
64 | Gson g = new Gson();
65 |
66 | @Nullable
67 | @Override
68 | public IBinder onBind(Intent intent) {
69 | if (mBinder == null) {
70 | mBinder = new MyBinder();
71 | }
72 | return mBinder;
73 | }
74 |
75 | Function scriptRunner = input -> {
76 | HashMap ret = new HashMap<>();
77 |
78 | if ((mBinder != null && mBinder.getCallback() != null)) {
79 |
80 | try {
81 | Bundle bundle = mBinder.getCallback().onEvent(0, input);
82 | ret.put("success", bundle.getBoolean("success", false));
83 | ret.put("data", bundle.getString("data", null));
84 | ret.put("err", bundle.getString("err", null));
85 | } catch (RemoteException e) {
86 | e.printStackTrace();
87 | }
88 | } else {
89 | ret.put("success", false);
90 | ret.put("data", null);
91 | ret.put("err", "LuEngine 未绑定");
92 | }
93 | return g.toJson(ret);
94 | };
95 |
96 | @Override
97 | public void onCreate() {
98 | super.onCreate();
99 | ServerApp.getInstance().setCallable(scriptRunner);
100 |
101 | }
102 |
103 | @Override
104 | public int onStartCommand(Intent intent, int flags, int startId) {
105 | return START_NOT_STICKY;
106 | }
107 |
108 | @Override
109 | public void onDestroy() {
110 | ServerApp.getInstance().setCallable(null);
111 | super.onDestroy();
112 | }
113 |
114 | private void stopServer() {
115 | ServerApp.getInstance().shutdown();
116 | }
117 |
118 | private int startServer() {
119 | ServerApp.getInstance().startUp();
120 |
121 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
122 | int importance = NotificationManager.IMPORTANCE_DEFAULT;
123 | NotificationChannel channel = new NotificationChannel("default", "default", importance);
124 | channel.setDescription("default");
125 | // Register the channel with the system; you can't change the importance
126 | // or other notification behaviors after this
127 | NotificationManager notificationManager = getSystemService(NotificationManager.class);
128 | notificationManager.createNotificationChannel(channel);
129 | }
130 |
131 |
132 | NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "default")
133 | .setSmallIcon(R.mipmap.ic_launcher)
134 | .setContentTitle("lu")
135 | .setContentText("雍和宫")
136 | .setPriority(NotificationCompat.PRIORITY_DEFAULT);
137 |
138 |
139 | startForeground(1, mBuilder.build());
140 | return 0;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/play/src/main/java/github/hotstu/lu/play/ModuleApp.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.play;
2 |
3 | import android.content.Context;
4 |
5 | import github.hotstu.lu.base.IModule;
6 |
7 | /**
8 | * @author hglf [hglf](https://github.com/hotstu)
9 | * @desc
10 | * @since 9/16/20
11 | */
12 | public class ModuleApp implements IModule {
13 | public static Context application;
14 | @Override
15 | public void onCreate(Context context) {
16 | application = context;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/play/src/main/java/github/hotstu/lu/play/ServerApp.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.play;
2 |
3 | import android.content.Context;
4 | import android.net.wifi.WifiInfo;
5 | import android.net.wifi.WifiManager;
6 | import android.text.format.Formatter;
7 |
8 | import com.google.gson.Gson;
9 |
10 | import java.io.BufferedInputStream;
11 | import java.io.IOException;
12 | import java.nio.charset.Charset;
13 | import java.util.HashMap;
14 |
15 | import fi.iki.elonen.NanoHTTPD;
16 | import okio.ByteString;
17 |
18 | public class ServerApp extends NanoHTTPD {
19 |
20 | private static ServerApp sInstance;
21 | private final Gson g;
22 | private final StaticHandler staticHandler;
23 | private Function scriptRunner;
24 | private String msg;
25 |
26 | public static ServerApp getInstance() {
27 | if (sInstance == null) {
28 | synchronized (ServerApp.class) {
29 | if (sInstance == null) {
30 | sInstance = new ServerApp();
31 | }
32 | }
33 | }
34 | return sInstance;
35 | }
36 |
37 | public ServerApp() {
38 | super("0.0.0.0", 8080);
39 | g = new Gson();
40 |
41 | staticHandler = new StaticHandler(ModuleApp.application);
42 | }
43 |
44 | public void startUp() {
45 | new Thread(() -> {
46 | try {
47 | WifiManager wifiManager = (WifiManager) ModuleApp.application.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
48 | WifiInfo connectionInfo = wifiManager.getConnectionInfo();
49 | int ipAddress = connectionInfo.getIpAddress();
50 | String address = Formatter.formatIpAddress(ipAddress);
51 | start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
52 | System.out.println(String.format("\nRunning! Point your browsers to http://%s:8080/ \n", address));
53 | } catch (IOException e) {
54 | e.printStackTrace();
55 | }
56 | }).start();
57 | }
58 |
59 | public void shutdown() {
60 | stop();
61 | }
62 |
63 | @Override
64 | public Response serve(IHTTPSession session) {
65 | final String uri = session.getUri();
66 | if (uri.matches("^/run$")) {
67 | HashMap files = new HashMap<>();
68 | try {
69 | session.parseBody(files);
70 | final String postData = files.get("postData");
71 | if (postData != null && !"".equals(postData)) {
72 | if (scriptRunner != null) {
73 | String result = scriptRunner.apply(postData);
74 | return newFixedLengthResponse(Response.Status.OK, "application/json", result);
75 | }
76 | }
77 | } catch (IOException | ResponseException e) {
78 | e.printStackTrace();
79 | }
80 | return newFixedLengthResponse(Response.Status.OK, "application/json", "{\"success\": false}");
81 | } else if (uri.matches("^/reset$")) {
82 | if (scriptRunner != null) {
83 | scriptRunner.apply("$context.resetContextScope()");
84 | }
85 | return newFixedLengthResponse(Response.Status.OK, "application/json", "{\"success\": true}");
86 | } else if (uri.matches("^/$")) {
87 | if (msg == null) {
88 | try (BufferedInputStream inputStream = new BufferedInputStream(ModuleApp.application.getAssets().open("form.html"));) {
89 | ByteString read = ByteString.read(inputStream, inputStream.available());
90 | msg = read.string(Charset.forName("UTF-8"));
91 | } catch (Throwable throwable) {
92 | throwable.printStackTrace();
93 | }
94 | }
95 | return newFixedLengthResponse(msg);
96 | } else if (staticHandler.isHandle(session)) {
97 | try {
98 | return staticHandler.handle(session);
99 | } catch (IOException e) {
100 | e.printStackTrace();
101 | return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, "text/html", "Error!");
102 | }
103 | } else {
104 | return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/html", "Page Not Found");
105 | }
106 |
107 |
108 | }
109 |
110 | public void setCallable(Function function) {
111 | this.scriptRunner = function;
112 | }
113 | }
--------------------------------------------------------------------------------
/play/src/main/java/github/hotstu/lu/play/StaticHandler.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.play;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.util.regex.Matcher;
8 | import java.util.regex.Pattern;
9 |
10 | import fi.iki.elonen.NanoHTTPD;
11 |
12 | public class StaticHandler {
13 |
14 | private final Context context;
15 | Pattern pattern = Pattern.compile("^/static/([\\s|\\S]*)$", Pattern.CASE_INSENSITIVE);
16 |
17 | public StaticHandler(Context context) {
18 | this.context = context;
19 | }
20 |
21 | public boolean isHandle(NanoHTTPD.IHTTPSession session) {
22 | final String uri = session.getUri();
23 | final Matcher matcher = pattern.matcher(uri);
24 | return matcher.find();
25 | }
26 |
27 | public NanoHTTPD.Response handle(NanoHTTPD.IHTTPSession session) throws IOException {
28 | final String uri = session.getUri();
29 | final Matcher matcher = pattern.matcher(uri);
30 | if (matcher.matches()) {
31 | final String subPath = matcher.group(1);
32 | //TODO 文件访问控制
33 | String mimeType = "application/octet-stream";
34 | if (subPath.endsWith("js")) {
35 | mimeType = "text/javascript";
36 | } else if (subPath.endsWith("css")) {
37 | mimeType = "text/css";
38 | } else if (subPath.endsWith("html")) {
39 | mimeType = "text/html";
40 | }
41 | final InputStream inputStream = context.getAssets().open("web/" + subPath);
42 | return NanoHTTPD.newChunkedResponse(NanoHTTPD.Response.Status.OK, mimeType, inputStream);
43 | }
44 | return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.NO_CONTENT,"application/octet-stream","");
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/play/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/play/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/play/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/play/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/play/src/main/resources/META-INF/services/github.hotstu.lu.base.IModule:
--------------------------------------------------------------------------------
1 | github.hotstu.lu.play.ModuleApp
--------------------------------------------------------------------------------
/render/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/render/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "30.0.2"
6 | compileOptions {
7 | sourceCompatibility 1.8
8 | targetCompatibility 1.8
9 | }
10 | defaultConfig {
11 | minSdkVersion 22
12 | targetSdkVersion 29
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: "libs", include: ["*.jar"])
29 | implementation 'androidx.appcompat:appcompat:1.2.0'
30 | implementation group: 'org.mozilla', name: 'rhino', version: '1.7.12'
31 | implementation project(path: ':engine')
32 |
33 |
34 | }
--------------------------------------------------------------------------------
/render/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hotstu/lu/f2c33abaf58bd569570c86c0d77d7e408a637770/render/consumer-rules.pro
--------------------------------------------------------------------------------
/render/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/render/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/render/src/main/assets/modules/ShadowModule.js:
--------------------------------------------------------------------------------
1 |
2 | const module = (calback) => {
3 | return {
4 | pre: (e) => {console.log('pre', '渲染前')},
5 | post: (e) => {console.log('post', '渲染后'), calback && calback()}
6 | }
7 | }
8 |
9 | export default module
10 |
--------------------------------------------------------------------------------
/render/src/main/assets/modules/phatomDomAPI.js:
--------------------------------------------------------------------------------
1 | module.exports = function($api) {
2 | return {
3 | createElement: (tag) => {
4 | console.log('createElement', tag);
5 | return $api.createComponent(tag)
6 | },
7 | createTextNode: (text) => {
8 | console.log('createTextNode', text);
9 | return $api.createText(text)
10 | },
11 | createComment: (text) => {
12 | console.log('createComment', text);
13 | return $api.createComment(text)
14 | },
15 | insertBefore: (parent, child, sibling) => {
16 | console.log('insertBefore', parent, child, sibling);
17 | parent.insertBefore(child, sibling)
18 | },
19 | removeChild: (parent, child) => {
20 | console.log('removeChild', parent, child);
21 | parent.removeChild(child)
22 | },
23 | appendChild: (parent, child) => {
24 | console.log('appendChild', parent, child);
25 | return parent.appendChild(child)
26 | },
27 | parentNode: (node) => {
28 | console.log('parentNode', node);
29 | return node.findParent();
30 | },
31 | nextSibling: (node) => {
32 | console.log('nextSibling', node);
33 | return node.findParent() && node.findParent().findNextSibling(node);
34 | },
35 | tagName: (node) => {
36 | console.log('tagName', node);
37 | return node.tag;
38 | },
39 | setTextContent: (node, text) => {
40 | console.log('setTextContent', node, text);
41 | $api.setTextContent(node, text)
42 | },
43 | getTextContent: (node) => {
44 | console.log('getTextContent', node);
45 | $api.getTextContent(node)
46 | },
47 | isElement: (node) => {
48 | console.log('isElement', node);
49 | return $api.isElement(node)
50 | },
51 | isText: (node) => {
52 | console.log('isText', node);
53 | return $api.isText(node)
54 | },
55 | isComment: (node) => {
56 | console.log('isComment', node);
57 | return $api.isComment(node)
58 | },
59 | };
60 | }
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/render/src/main/assets/modules/snabbdom-class.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.snabbdom_class = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o createComponent(String tag) {
23 | return new Frame(context, tag);
24 | }
25 |
26 | public NativeComponent> createText(String text) {
27 | return new Text(context, text);
28 | }
29 |
30 | public NativeComponent> createComment(String text) {
31 | return new Comment(context, text);
32 | }
33 |
34 | public boolean isComment(NativeComponent> node) {
35 | return node instanceof Comment;
36 | }
37 |
38 | public boolean isText(NativeComponent> node) {
39 | return node instanceof Text;
40 | }
41 |
42 | public boolean isElement(NativeComponent> node) {
43 | return node instanceof Frame;
44 | }
45 |
46 | public void setTextContent(NativeComponent> node, String text) {
47 | if (node.children.get(0) instanceof Text) {
48 | ((Text) node.children.get(0)).setText(text);
49 | }
50 | }
51 |
52 | public String getTextContent(NativeComponent> node) {
53 | if (node.children.get(0) instanceof Text) {
54 | return ((Text) node.children.get(0)).text;
55 | }
56 | return null;
57 | }
58 |
59 |
60 | public void debug(String what, Object... component) {
61 | System.out.println(what + "==>" + component);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/RenderContext.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Looper;
6 | import android.transition.TransitionManager;
7 | import android.util.Log;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 |
11 | import org.mozilla.javascript.NativeObject;
12 | import org.mozilla.javascript.Scriptable;
13 |
14 | import java.util.ArrayList;
15 |
16 | import github.hotstu.lu.engine.LuContext;
17 | import github.hotstu.lu.engine.LuEngine;
18 | import github.hotstu.lu.render.component.Frame;
19 | import github.hotstu.lu.render.style.SimpleStyleEngine;
20 |
21 |
22 | /**
23 | * @author hglf [hglf](https://github.com/hotstu)
24 | * @desc
25 | * @since 9/11/20
26 | */
27 | public class RenderContext extends LuContext {
28 | private final Context mContext;
29 | private final String id;
30 | private final Handler mMainHandler;
31 | private Handler mWokerHandler;
32 | private final NativeRenderAPI api;
33 | private Frame frame;
34 | private SimpleStyleEngine mStyle;
35 |
36 | public RenderContext(Context ctx, String id) {
37 | super();
38 | this.mContext = ctx;
39 | this.id = id;
40 | this.mMainHandler = new Handler(Looper.getMainLooper());
41 | this.mWokerHandler = new Handler(LuEngine.getInstance().getWorkerHandler().getLooper());
42 | this.api = new NativeRenderAPI(this);
43 | this.mStyle = new SimpleStyleEngine();
44 | }
45 |
46 | public Frame wrap(LinearLayout view) {
47 | if (frame != null) {
48 | throw new IllegalStateException("context already wrapped with a root view");
49 | }
50 | frame = new Frame(this, view);
51 | return frame;
52 | }
53 |
54 | public NativeComponent> getRootComponent() {
55 | return frame;
56 | }
57 |
58 | public Context getContext() {
59 | return mContext;
60 | }
61 |
62 | public SimpleStyleEngine getStyle() {
63 | return mStyle;
64 | }
65 |
66 | public NativeRenderAPI getApi() {
67 | return api;
68 | }
69 |
70 | public void destroy() {
71 | //TODO
72 | }
73 |
74 | private final ArrayList pendingTasks = new ArrayList<>();
75 | private final Runnable paddingRunnable = () -> {
76 | ArrayList tasks;
77 | synchronized (pendingTasks) {
78 | tasks = new ArrayList<>(pendingTasks);
79 | pendingTasks.clear();
80 | }
81 | Log.d("RC", "post run async in batch:" + tasks.size());
82 |
83 | TransitionManager.beginDelayedTransition((ViewGroup) getRootComponent().mView);
84 | for (Runnable task : tasks) {
85 | task.run();
86 | }
87 | };
88 | /**
89 | * run in ui thread
90 | *
91 | * @param runnable
92 | */
93 | public void post(Runnable runnable) {
94 | if (Looper.myLooper() == mMainHandler.getLooper()) {
95 | Log.d("RC", "post run sync");
96 | runnable.run();
97 | } else {
98 | synchronized (this.pendingTasks) {
99 | this.pendingTasks.add(runnable);
100 | }
101 | this.mMainHandler.removeCallbacks(paddingRunnable);
102 | this.mMainHandler.post(paddingRunnable);
103 | }
104 | }
105 |
106 | /**
107 | * run in worker Thread
108 | * @param runnable
109 | */
110 | public void postWorker(Runnable runnable) {
111 | if (Looper.myLooper() == mWokerHandler.getLooper()) {
112 | runnable.run();
113 | } else {
114 | this.mWokerHandler.post(runnable);
115 | }
116 | }
117 |
118 | @Override
119 | protected void onContextScopeCreated(Scriptable scope) {
120 | LuEngine.getInstance().putProperty(scope, "$context", this);
121 | }
122 |
123 | public void attachStyles(Object o) {
124 | mStyle.attach((NativeObject) o);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/component/Comment.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.component;
2 |
3 | import android.view.View;
4 |
5 | import github.hotstu.lu.render.NativeComponent;
6 | import github.hotstu.lu.render.RenderContext;
7 |
8 |
9 | /**
10 | * @author hglf [hglf](https://github.com/hotstu)
11 | * @desc
12 | * @since 9/14/20
13 | */
14 | public class Comment extends NativeComponent {
15 |
16 | public String text;
17 |
18 | public Comment(RenderContext context, String text) {
19 | super(context, "!");
20 | this.text = text;
21 | }
22 |
23 | @Override
24 | protected void onAttachChild(NativeComponent> child) {
25 | throw new IllegalStateException("should never happen");
26 | }
27 |
28 | @Override
29 | protected void onAttachChild(NativeComponent> child, int index) {
30 | throw new IllegalStateException("should never happen");
31 | }
32 |
33 | @Override
34 | protected void onDetachChild(NativeComponent> child) {
35 | throw new IllegalStateException("should never happen");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/component/Frame.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.component;
2 |
3 | import android.widget.LinearLayout;
4 |
5 | import org.mozilla.javascript.NativeObject;
6 |
7 | import java.util.Iterator;
8 |
9 | import github.hotstu.lu.render.NativeComponent;
10 | import github.hotstu.lu.render.RenderContext;
11 | import github.hotstu.lu.render.widget.LuLinearLayout;
12 |
13 |
14 | /**
15 | * @author hglf [hglf](https://github.com/hotstu)
16 | * @desc
17 | * @since 9/10/20
18 | */
19 | public class Frame extends NativeComponent {
20 | public Frame(RenderContext context, LinearLayout view) {
21 | super(context, "ROOT");
22 | this.mView = view;
23 | }
24 |
25 | public Frame(RenderContext context, String tag) {
26 | super(context, tag);
27 | LuLinearLayout mView = new LuLinearLayout(context.getContext());
28 | mView.setOrientation(LinearLayout.VERTICAL);
29 | mView.setComponent(this);
30 | //Random random = new Random();
31 | //int[] colors = new int[]{Color.GREEN, Color.RED, Color.BLUE};
32 |
33 |
34 | //mView.setBackgroundColor(colors[random.nextInt(colors.length)]);
35 | //mView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
36 | this.mView = mView;
37 |
38 | }
39 |
40 | @Override
41 | public void setAttribute(String attr, String value) {
42 | super.setAttribute(attr, value);
43 | }
44 |
45 | @Override
46 | protected void onAttachChild(NativeComponent> child) {
47 | //TODO batch update view
48 | if (child.getView() != null) {
49 | mRenderContext.post(() -> {
50 | this.mView.addView(child.getView());
51 | child.onAttached();
52 | });
53 | }
54 | }
55 |
56 | @Override
57 | protected void onAttachChild(NativeComponent> child, int index) {
58 | //TODO batch update view
59 | if (child.getView() != null) {
60 | mRenderContext.post(() -> {
61 | this.mView.addView(child.getView(), index);
62 | child.onAttached();
63 | });
64 | }
65 |
66 | }
67 |
68 | @Override
69 | protected void onDetachChild(NativeComponent> child) {
70 | mRenderContext.post(() -> {
71 | this.mView.removeView(child.getView());
72 | });
73 | }
74 |
75 | @Override
76 | public void onAttached() {
77 | super.onAttached();
78 | }
79 |
80 |
81 |
82 | @Override
83 | public void onApplyStyle(NativeObject o) {
84 | super.onApplyStyle(o);
85 | Iterator> iterator = o.keySet().iterator();
86 | while (iterator.hasNext()) {
87 | String next = (String) iterator.next();
88 | String value = (String) o.get(next);
89 | switch (next) {
90 | case "orientation":
91 | mView.setOrientation(parseOrientation(value));
92 | break;
93 | case "gravity":
94 | mView.setGravity(parseGravity(value));
95 | break;
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/component/Text.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.component;
2 |
3 | import android.view.Gravity;
4 | import android.widget.LinearLayout;
5 | import android.widget.TextView;
6 |
7 | import github.hotstu.lu.render.NativeComponent;
8 | import github.hotstu.lu.render.RenderContext;
9 |
10 |
11 | /**
12 | * @author hglf [hglf](https://github.com/hotstu)
13 | * @desc
14 | * @since 9/10/20
15 | */
16 | public class Text extends NativeComponent {
17 | public String text;
18 |
19 | public Text(RenderContext context, String text) {
20 | super(context, null);
21 | this.text = text;
22 | this.mView = new TextView(context.getContext());
23 | this.mView.setText(this.text);
24 | }
25 |
26 | @Override
27 | protected void onAttachChild(NativeComponent> child) {
28 | throw new IllegalStateException("should never happen");
29 | }
30 |
31 | @Override
32 | protected void onAttachChild(NativeComponent> child, int index) {
33 | throw new IllegalStateException("should never happen");
34 | }
35 |
36 | @Override
37 | protected void onDetachChild(NativeComponent> child) {
38 | throw new IllegalStateException("should never happen");
39 | }
40 |
41 | @Override
42 | public void onAttached() {
43 | super.onAttached();
44 | if (this.mView.getLayoutParams() != null) {
45 | ((LinearLayout.LayoutParams) this.mView.getLayoutParams()).gravity = Gravity.CENTER;
46 | }
47 | this.mView.setText(this.text);
48 |
49 | }
50 |
51 | public void setText(String text) {
52 | this.text = text;
53 | mRenderContext.post(() -> {
54 | this.mView.setText(this.text);
55 | });
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/event/Event.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.event;
2 |
3 | /**
4 | * @author hglf [hglf](https://github.com/hotstu)
5 | * @desc
6 | * @since 9/11/20
7 | */
8 | public class Event {
9 | public String type;
10 | public Object target;
11 | }
12 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/event/LuClickHandler.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.event;
2 |
3 | import android.view.View;
4 |
5 | import org.mozilla.javascript.Context;
6 | import org.mozilla.javascript.Function;
7 |
8 | import github.hotstu.lu.render.R;
9 | import github.hotstu.lu.render.RenderContext;
10 |
11 | /**
12 | * @author hglf [hglf](https://github.com/hotstu)
13 | * @desc
14 | * @since 9/21/20
15 | */
16 | public class LuClickHandler implements View.OnClickListener {
17 |
18 | final String event;
19 | final RenderContext context;
20 | final Function func;
21 |
22 | public LuClickHandler(final String event, final Function func, final RenderContext context) {
23 | this.event = event;
24 | this.func = func;
25 | this.context = context;
26 | }
27 |
28 | public static void removeEventListener(View v, String event, Function func) {
29 | if (v.getTag(R.id.tag_event_click) != null) {
30 | v.setOnClickListener(null);
31 | v.setTag(R.id.tag_event_click, null);
32 |
33 | }
34 | }
35 |
36 | public LuClickHandler attach(View v) {
37 | v.setTag(R.id.tag_event_click, this);
38 | v.setOnClickListener(this);
39 | return this;
40 | }
41 |
42 | @Override
43 | public void onClick(View v) {
44 | Event e = new Event();
45 | e.type = event;
46 | context.postWorker(() -> func.call(Context.getCurrentContext(),
47 | context.getContextScope(), null, new Object[]{e}));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/module/ClassManager.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.module;
2 |
3 | import java.util.Arrays;
4 | import java.util.Iterator;
5 | import java.util.TreeSet;
6 |
7 | import github.hotstu.lu.render.NativeComponent;
8 | import github.hotstu.lu.render.RenderContext;
9 |
10 | /**
11 | * @author hglf [hglf](https://github.com/hotstu)
12 | * @desc
13 | * @since 9/21/20
14 | */
15 | public class ClassManager {
16 | //TODO support remove style when class removed
17 | private final TreeSet clazzes = new TreeSet<>();
18 | private final NativeComponent> compoent;
19 |
20 | public ClassManager(NativeComponent> component) {
21 | this.compoent = component;
22 | }
23 |
24 | public void addClass(String clazz) {
25 | boolean add = clazzes.add(clazz);
26 | if (add) {
27 | update();
28 | }
29 | }
30 |
31 | public Iterator it() {
32 | return clazzes.iterator();
33 | }
34 |
35 | public void removeClass(String clazz) {
36 | boolean remove = clazzes.remove(clazz);
37 | if (remove) {
38 | update();
39 | }
40 | }
41 |
42 | public void setClass(String... clazzes) {
43 | this.clazzes.clear();
44 | this.clazzes.addAll(Arrays.asList(clazzes));
45 | update();
46 | }
47 |
48 | public void update() {
49 | RenderContext renderContext = compoent.getRenderContext();
50 | if (renderContext.getStyle() != null) {
51 | renderContext.getStyle().applyTo(compoent);
52 | }
53 | }
54 |
55 | public boolean hasClass(String clazz) {
56 | return this.clazzes.contains(clazz);
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/style/SimpleStyleEngine.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.style;
2 |
3 | import org.mozilla.javascript.NativeObject;
4 |
5 | import java.util.Iterator;
6 |
7 | import github.hotstu.lu.render.NativeComponent;
8 |
9 | /**
10 | * @author hglf [hglf](https://github.com/hotstu)
11 | * @desc 目前对css的支持只是简单处理(非常简单, 需要完善)
12 | * @since 9/21/20
13 | */
14 | public class SimpleStyleEngine {
15 | private NativeObject mJss;
16 |
17 | public void attach(NativeObject jss) {
18 | this.mJss = jss;
19 | }
20 |
21 | public void applyTo(NativeComponent> component) {
22 | Iterator it = component.getClassManager().it();
23 | while (it.hasNext()) {
24 | final String next = it.next();
25 | if (mJss.containsKey(next)) {
26 | component.onApplyStyle((NativeObject) mJss.get(next));
27 | }
28 | }
29 | }
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/render/src/main/java/github/hotstu/lu/render/widget/LuLinearLayout.java:
--------------------------------------------------------------------------------
1 | package github.hotstu.lu.render.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.LinearLayout;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | import github.hotstu.lu.render.NativeComponent;
11 |
12 |
13 | /**
14 | * @author hglf [hglf](https://github.com/hotstu)
15 | * @desc
16 | * @since 9/14/20
17 | */
18 | public class LuLinearLayout extends LinearLayout {
19 | NativeComponent> component;
20 | public LuLinearLayout(Context context) {
21 | super(context);
22 | }
23 |
24 | public void setComponent(NativeComponent> component) {
25 | this.component = component;
26 | }
27 |
28 | public LuLinearLayout(Context context, @Nullable AttributeSet attrs) {
29 | super(context, attrs);
30 | }
31 |
32 | public LuLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
33 | super(context, attrs, defStyleAttr);
34 | }
35 |
36 | @Override
37 | public void addView(View child, int index) {
38 | super.addView(child, index);
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return "CpLinear{" +
44 | "component=" + component +
45 | '}';
46 | }
47 |
48 | @Override
49 | public void removeView(View view) {
50 | super.removeView(view);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/render/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':base'
2 | include ':engine'
3 | include ':render'
4 | include ':play'
5 | include ':app'
6 | rootProject.name = "lu"
--------------------------------------------------------------------------------