From 08d1188b339acb243770d6443a374d85ef135154 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 25 Oct 2017 00:15:47 +0800 Subject: [PATCH] add: * offline docs * tow-row input method enhance bar * long press hint to show function manual * docs drawer --- app/src/main/AndroidManifest.xml | 4 +- .../addon/autojs/autojs-global-scope.js | 634 +++++++++--------- .../codemirror/addon/autojs/autojs-hint.js | 171 +++++ .../editor/codemirror/addon/hint/show-hint.js | 3 +- app/src/main/assets/editor/index.html | 12 +- app/src/main/assets/help/catalogue.json | 310 --------- .../help/developerguide/如何写自动操作脚本.md | 16 - .../Android7.0以上点按与手势模拟.md | 79 --- .../assets/help/documentation/shell命令.md | 385 ----------- .../assets/help/documentation/一般常用函数.md | 85 --- .../documentation/事件与按键、触摸监听.md | 414 ------------ .../help/documentation/图片与图色处理.md | 179 ----- .../help/documentation/如何阅读本文档.md | 30 - .../main/assets/help/documentation/定时器.md | 50 -- .../assets/help/documentation/常见问题.md | 50 -- .../main/assets/help/documentation/应用.md | 46 -- .../assets/help/documentation/控制台与输出.md | 56 -- .../assets/help/documentation/文件读写.md | 198 ------ .../help/documentation/模块与第三方jar.md | 23 - .../assets/help/documentation/简介与说明.md | 3 - .../assets/help/documentation/脚本引擎.md | 56 -- .../assets/help/documentation/自动操作函数.md | 95 --- .../assets/help/documentation/调用Java API.md | 162 ----- .../main/assets/help/documentation/选择器.md | 573 ---------------- .../需要Root权限的自动操作函数.md | 176 ----- .../需要Root权限的触摸与多点触摸.md | 71 -- .../assets/help/w3c/Function 对象(类).html | 148 ---- .../main/assets/help/w3c/arguments 对象.html | 85 --- .../help/w3c/break 和 continue 语句.html | 114 ---- app/src/main/assets/help/w3c/if 语句.html | 77 --- app/src/main/assets/help/w3c/switch 语句.html | 98 --- app/src/main/assets/help/w3c/with 语句.html | 41 -- app/src/main/assets/help/w3c/一元运算符.html | 215 ------ app/src/main/assets/help/w3c/乘性运算符.html | 88 --- app/src/main/assets/help/w3c/位运算符.html | 357 ---------- app/src/main/assets/help/w3c/保留字.html | 70 -- app/src/main/assets/help/w3c/修改对象.html | 179 ----- app/src/main/assets/help/w3c/值.html | 56 -- app/src/main/assets/help/w3c/关系运算符.html | 91 --- app/src/main/assets/help/w3c/关键字.html | 60 -- app/src/main/assets/help/w3c/函数概述.html | 121 ---- app/src/main/assets/help/w3c/加性运算符.html | 88 --- app/src/main/assets/help/w3c/原始类型.html | 286 -------- app/src/main/assets/help/w3c/变量.html | 191 ------ .../main/assets/help/w3c/定义类或对象.html | 455 ------------- app/src/main/assets/help/w3c/对象作用域.html | 148 ---- app/src/main/assets/help/w3c/对象应用.html | 80 --- app/src/main/assets/help/w3c/对象类型.html | 86 --- app/src/main/assets/help/w3c/引用类型.html | 418 ------------ app/src/main/assets/help/w3c/条件运算符.html | 34 - app/src/main/assets/help/w3c/标签语句.html | 34 - app/src/main/assets/help/w3c/等性运算符.html | 145 ---- app/src/main/assets/help/w3c/类型转换.html | 282 -------- .../main/assets/help/w3c/继承机制实例.html | 34 - .../main/assets/help/w3c/继承机制实现.html | 329 --------- app/src/main/assets/help/w3c/语法.html | 105 --- app/src/main/assets/help/w3c/赋值运算符.html | 55 -- app/src/main/assets/help/w3c/迭代语句.html | 108 --- app/src/main/assets/help/w3c/逗号运算符.html | 30 - app/src/main/assets/help/w3c/逻辑运算符.html | 294 -------- .../main/assets/help/w3c/闭包(closure).html | 68 -- .../main/assets/help/w3c/面向对象技术.html | 61 -- .../java/com/stardust/scriptdroid/Pref.java | 3 + .../ui/doc/DocumentationActivity.java | 48 ++ .../scriptdroid/ui/doc/ManualDialog.java | 83 +++ .../ui/{main => }/doc/OnlineDocsFragment.java | 11 +- .../scriptdroid/ui/edit/CodeMirrorEditor.java | 6 +- .../scriptdroid/ui/edit/EditActivity.java | 4 + .../scriptdroid/ui/edit/EditorView.java | 127 ++-- .../ui/edit/ViewSampleActivity.java | 3 +- .../ui/edit/completion/CodeCompletionBar.java | 32 +- .../ui/edit/completion/CodeCompletions.java | 14 +- .../ui/edit/completion/Symbols.java | 4 +- .../ui/help/DocumentationActivity.java | 105 --- .../ui/help/HelpCatalogueActivity.java | 216 ------ .../ui/help/LocalWebViewActivity.java | 77 --- .../scriptdroid/ui/main/MainActivity.java | 2 +- .../java/com/stardust/widget/EWebView.java | 2 +- app/src/main/res/drawable/ic_ali_close.png | Bin 0 -> 976 bytes .../main/res/drawable/ic_ali_fullscreen.png | Bin 0 -> 1825 bytes app/src/main/res/drawable/ic_ali_fx.png | Bin 0 -> 2691 bytes .../main/res/drawable/ic_ali_pin_to_left.png | Bin 0 -> 1091 bytes ...ocument.xml => activity_documentation.xml} | 23 +- app/src/main/res/layout/editor_view.xml | 80 ++- .../res/layout/floating_manual_dialog.xml | 72 ++ 85 files changed, 848 insertions(+), 9076 deletions(-) create mode 100644 app/src/main/assets/editor/codemirror/addon/autojs/autojs-hint.js delete mode 100644 app/src/main/assets/help/catalogue.json delete mode 100644 app/src/main/assets/help/developerguide/如何写自动操作脚本.md delete mode 100644 app/src/main/assets/help/documentation/Android7.0以上点按与手势模拟.md delete mode 100644 app/src/main/assets/help/documentation/shell命令.md delete mode 100644 app/src/main/assets/help/documentation/一般常用函数.md delete mode 100644 app/src/main/assets/help/documentation/事件与按键、触摸监听.md delete mode 100644 app/src/main/assets/help/documentation/图片与图色处理.md delete mode 100644 app/src/main/assets/help/documentation/如何阅读本文档.md delete mode 100644 app/src/main/assets/help/documentation/定时器.md delete mode 100644 app/src/main/assets/help/documentation/常见问题.md delete mode 100644 app/src/main/assets/help/documentation/应用.md delete mode 100644 app/src/main/assets/help/documentation/控制台与输出.md delete mode 100644 app/src/main/assets/help/documentation/文件读写.md delete mode 100644 app/src/main/assets/help/documentation/模块与第三方jar.md delete mode 100644 app/src/main/assets/help/documentation/简介与说明.md delete mode 100644 app/src/main/assets/help/documentation/脚本引擎.md delete mode 100644 app/src/main/assets/help/documentation/自动操作函数.md delete mode 100644 app/src/main/assets/help/documentation/调用Java API.md delete mode 100644 app/src/main/assets/help/documentation/选择器.md delete mode 100644 app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md delete mode 100644 app/src/main/assets/help/documentation/需要Root权限的触摸与多点触摸.md delete mode 100644 app/src/main/assets/help/w3c/Function 对象(类).html delete mode 100644 app/src/main/assets/help/w3c/arguments 对象.html delete mode 100644 app/src/main/assets/help/w3c/break 和 continue 语句.html delete mode 100644 app/src/main/assets/help/w3c/if 语句.html delete mode 100644 app/src/main/assets/help/w3c/switch 语句.html delete mode 100644 app/src/main/assets/help/w3c/with 语句.html delete mode 100644 app/src/main/assets/help/w3c/一元运算符.html delete mode 100644 app/src/main/assets/help/w3c/乘性运算符.html delete mode 100644 app/src/main/assets/help/w3c/位运算符.html delete mode 100644 app/src/main/assets/help/w3c/保留字.html delete mode 100644 app/src/main/assets/help/w3c/修改对象.html delete mode 100644 app/src/main/assets/help/w3c/值.html delete mode 100644 app/src/main/assets/help/w3c/关系运算符.html delete mode 100644 app/src/main/assets/help/w3c/关键字.html delete mode 100644 app/src/main/assets/help/w3c/函数概述.html delete mode 100644 app/src/main/assets/help/w3c/加性运算符.html delete mode 100644 app/src/main/assets/help/w3c/原始类型.html delete mode 100644 app/src/main/assets/help/w3c/变量.html delete mode 100644 app/src/main/assets/help/w3c/定义类或对象.html delete mode 100644 app/src/main/assets/help/w3c/对象作用域.html delete mode 100644 app/src/main/assets/help/w3c/对象应用.html delete mode 100644 app/src/main/assets/help/w3c/对象类型.html delete mode 100644 app/src/main/assets/help/w3c/引用类型.html delete mode 100644 app/src/main/assets/help/w3c/条件运算符.html delete mode 100644 app/src/main/assets/help/w3c/标签语句.html delete mode 100644 app/src/main/assets/help/w3c/等性运算符.html delete mode 100644 app/src/main/assets/help/w3c/类型转换.html delete mode 100644 app/src/main/assets/help/w3c/继承机制实例.html delete mode 100644 app/src/main/assets/help/w3c/继承机制实现.html delete mode 100644 app/src/main/assets/help/w3c/语法.html delete mode 100644 app/src/main/assets/help/w3c/赋值运算符.html delete mode 100644 app/src/main/assets/help/w3c/迭代语句.html delete mode 100644 app/src/main/assets/help/w3c/逗号运算符.html delete mode 100644 app/src/main/assets/help/w3c/逻辑运算符.html delete mode 100644 app/src/main/assets/help/w3c/闭包(closure).html delete mode 100644 app/src/main/assets/help/w3c/面向对象技术.html create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/doc/DocumentationActivity.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/doc/ManualDialog.java rename app/src/main/java/com/stardust/scriptdroid/ui/{main => }/doc/OnlineDocsFragment.java (83%) delete mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentationActivity.java delete mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/help/HelpCatalogueActivity.java delete mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/help/LocalWebViewActivity.java create mode 100644 app/src/main/res/drawable/ic_ali_close.png create mode 100644 app/src/main/res/drawable/ic_ali_fullscreen.png create mode 100644 app/src/main/res/drawable/ic_ali_fx.png create mode 100644 app/src/main/res/drawable/ic_ali_pin_to_left.png rename app/src/main/res/layout/{activity_document.xml => activity_documentation.xml} (59%) create mode 100644 app/src/main/res/layout/floating_manual_dialog.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f1983935..965a730e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -71,18 +71,16 @@ android:multiprocess="true"> - - - + diff --git a/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js index 0e9606e1..647d2ad5 100644 --- a/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js +++ b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-global-scope.js @@ -1,338 +1,306 @@ function autoJsGlobalScope(){ - var globals = { - "modules": [ - "app", - "automator", - "console", - "dialogs", - "events", - "images", - "files", - "timers", - "ui", - ], - "app": [ - "launchPackage", - "launch", - "launchApp", - "getPackageName", - "openAppSetting" - ], - "automator": [ - "click", - "longClick", - "press", - "swipe", - "gesture", - "gestures", - "gestureAsync", - "gesturesAsync", - "scrollDown", - "scrollUp", - "input", - "setText" - ], - "console": [ - "print", - "log", - "err", - "openConsole", - "clearConsole" - ], - "dialogs": [ - "rawInput", - "input", - "alert", - "confirm", - "prompt" - ], - "images": [ - "requestScreenCapture", - "captureScreen", - "findColor", - "findColorInRegion", - "findColorEquals" - ], - "files": [ - "open" - ], - "selector": [ - "id", - "idContains", - "idStartsWith", - "idEndsWith", - "idMatches", - "text", - "textContains", - "textStartsWith", - "textEndsWith", - "textMatches", - "desc", - "descContains", - "descStartsWith", - "descEndsWith", - "descMatches", - "className", - "classNameContains", - "classNameStartsWith", - "classNameEndsWith", - "classNameMatches", - "packageName", - "packageNameContains", - "packageNameStartsWith", - "packageNameEndsWith", - "packageNameMatches", - "bounds", - "boundsInside", - "boundsContains", - "drawingOrder", - "checkable", - "checked", - "focusable", - "focused", - "visibleToUser", - "accessibilityFocused", - "selected", - "clickable", - "longClickable", - "enabled", - "password", - "scrollable", - "editable", - "contentInvalid", - "contextClickable", - "multiLine", - "dismissable", - "checkable", - "checked", - "focusable", - "focused", - "visibleToUser", - "accessibilityFocused", - "selected", - "clickable", - "longClickable", - "enabled", - "password", - "scrollable", - "editable", - "contentInvalid", - "contextClickable", - "multiLine", - "dismissable" - ], - "shell": [ - "SetScreenMetrics", - "Tap", - "Swipe", - "Screencap", - "KeyCode", - "Home", - "Back", - "Power", - "Up", - "Down", - "Left", - "Right", - "OK", - "VolumeUp", - "VolumeDown", - "Menu", - "Camera", - "Text" - ], - "timers": [ - "loop", - "setTimeout", - "clearTimeout", - "setInterval", - "clearInterval", - "setImmediate", - "clearImmediate" - ], - "web": [ - "newInjectableWebClient", - "newInjectableWebView" - ], - "general": [ - "toast", - "toastLog", - "sleep", - "isStopped", - "notStopped", - "exit", - "setClip", - "getClip", - "currentPackage", - "currentActivity", - "waitForActivity", - "waitForPackage", - "setScreenMetrics" - ], - "variables": [ - "context", - "activity" - ] - }; - var modules = { - "app": [ - "uninstall", - "viewFile", - "editFile", - "openUrl", - "launchPackage", - "launch", - "launchApp", - "getPackageName", - "openAppSetting" - ], - "automator": [ - "click", - "longClick", - "press", - "swipe", - "gesture", - "gestures", - "gestureAsync", - "gesturesAsync", - "scrollDown", - "scrollUp", - "input", - "setText" - ], - "console": [ - "show", - "hide", - "clear", - "verbose", - "print", - "info", - "log", - "warn", - "error", - "assert" - ], - "dialogs": [ - "select", - "singleChoice", - "multiChoice", - "rawInput", - "input", - "alert", - "confirm", - "prompt" - ], - "images": [ - "saveImage", - "pixel", - "read", - "requestScreenCapture", - "captureScreen", - "findColor", - "findColorInRegion", - "findColorEquals" - ], - "colors": [ - "red", - "green", - "blue", - "alpha", - "toString", - "rgb", - "argb" - ], - "events": [ - "emitter", - "observeKey", - "observeTouch", - "observeNotification", - "onKeyDown", - "onKeyUp", - "onceKeyDown", - "onceKeyUp", - "onToast", - "onNotification", - "removeAllKeyDownListeners", - "removeAllKeyUpListeners", - "onTouch", - "removeAllTouchListeners", - "getTouchEventTimeout", - "setTouchEventTimeout", - "on", - "once", - "emit", - "getListeners", - "addListener", - "eventNames", - "listenerCount", - "listeners", - "prependListener", - "prependOnceListener", - "removeAllListeners", - "removeAllListeners", - "removeListener", - "setMaxListeners", - "getMaxListeners", - "defaultMaxListeners" - ], - "files": [ - "open", - "isFile", - "isDir", - "isEmptyDir", - "join", - "create", - "createIfNotExists", - "exists", - "ensureDir", - "read", - "write", - "copy", - "rename", - "renameWithoutExtension", - "getName", - "getExtension", - "remove", - "removeDir", - "getSdcardPath", - "listDir" - ], - "timers": [ - "loop", - "setTimeout", - "clearTimeout", - "setInterval", - "clearInterval", - "setImmediate", - "clearImmediate" - ] - }; - function for_each(obj, func){ - for(var key in obj){ - if(!obj.hasOwnProperty(key)){ - continue; - } - func(key, obj[key]); + function FUNCTION(url){ + var f = function(){}; + f.__url__ = url; + return f; + } + function VARIABLE(url){ + return { + __url__: url } } - var __global__ = {}; - for_each(modules, function(moduleName, moduleVariables){ - if(!__global__[moduleName]){ - __global__[moduleName] = {}; - } - for(var i = 0; i < moduleVariables.length; i++){ - if(!__global__[moduleName][moduleVariables[i]]){ - __global__[moduleName][moduleVariables[i]] = ''; - } - } - }); - for_each(globals, function(moduleName, moduleVariables){ - for(var i = 0; i < moduleVariables.length; i++){ - if(!__global__[moduleVariables[i]]){ - __global__[moduleVariables[i]] = ''; - } - } - }) - return __global__; + var app = { + "uninstall": FUNCTION("app.html#app_app_uninstall_packagename"), + "viewFile": FUNCTION("app.html#app_app_viewfile_path"), + "editFile": FUNCTION("app.html#app_app_editfile_path"), + "openUrl": FUNCTION("app.html#app_app_openurl_url"), + "launchPackage": FUNCTION("app.html#app_app_takephoto_path"), + "launch": FUNCTION("globals.html#globals_launchpackage_packagename"), + "launchApp": FUNCTION("globals.html#globals_launchapp_appname"), + "getPackageName": FUNCTION("globals.html#globals_getpackagename_appname"), + "openAppSetting": FUNCTION("globals.html#globals_getappname_packagename"), + __url__: "app.html" + }; + var automator = { + "click": FUNCTION("widgets-based-automation.html#widgets_based_automation_click_text_i"), + "longClick": FUNCTION("widgets-based-automation.html#widgets_based_automation_longclick_text_i"), + "press": FUNCTION(), + "swipe": FUNCTION(), + "gesture": FUNCTION(), + "gestures": FUNCTION(), + "gestureAsync": FUNCTION(), + "gesturesAsync": FUNCTION(), + "scrollDown": FUNCTION("widgets-based-automation.html#widgets_based_automation_scrollup_i"), + "scrollUp": FUNCTION("widgets-based-automation.html#widgets_based_automation_scrollup_i"), + "input": FUNCTION("widgets-based-automation.html#widgets_based_automation_input_i_text"), + "setText": FUNCTION("widgets-based-automation.html#widgets_based_automation_settext_i_text"), + __url__: "widgets-based-automation.html" + }; + var console = { + "show": FUNCTION("console.html#console_console_show"), + "hide": FUNCTION(), + "clear": FUNCTION("console.html#console_console_clear"), + "verbose": FUNCTION("console.html#console_console_verbose_data_args"), + "info": FUNCTION("console.html#console_console_info_data_args"), + "log": FUNCTION("console.html#console_console_log_data_args"), + "warn": FUNCTION("console.html#console_console_warn_data_args"), + "error": FUNCTION("console.html#console_console_error_data_args"), + "assert": FUNCTION("console.html#console_console_assert_value_message"), + __url__: "console.html" + }; + var dialogs = { + "select": FUNCTION(), + "singleChoice": FUNCTION(), + "multiChoice": FUNCTION(), + "rawInput": FUNCTION(), + "input": FUNCTION(), + "alert": FUNCTION(), + "confirm": FUNCTION(), + "prompt": FUNCTION() + }; + var images = { + "saveImage": FUNCTION("images.html#images_images_saveimage_image_path"), + "pixel": FUNCTION("images.html#images_images_pixel_image_x_y"), + "read": FUNCTION(), + "requestScreenCapture": FUNCTION("images.html#images_requestscreencapture_width_height"), + "captureScreen": FUNCTION("images.html#images_capturescreen"), + "findColor": FUNCTION("images.html#images_images_findcolor_image_color_options"), + "findColorInRegion": FUNCTION("images.html#images_images_findcolorinregion_img_color_x_y_width_height_threads_algorithm_threshold"), + "findColorEquals": FUNCTION("images.html#images_images_findcolorequals_img_color_x_y_width_height_threads"), + __url__: "images.html" + }; + var colors = { + "red": FUNCTION("images.html#images_colors_red_color"), + "green": FUNCTION("images.html#images_colors_green_color"), + "blue": FUNCTION("images.html#images_colors_blue_color"), + "alpha": FUNCTION("images.html#images_colors_alpha_color"), + "toString": FUNCTION("images.html#images_colors_tostring_color"), + "rgb": FUNCTION("images.html#images_colors_rgb_red_green_blue"), + "argb": FUNCTION("images.html#images_colors_argb_alpha_red_green_blue"), + __url__: "images.html#images_colors" + }; + var events = { + "emitter": FUNCTION("events.html#events_events_emitter"), + "observeKey": FUNCTION("events.html#events_events_observekey"), + "observeTouch": FUNCTION("events.html#events_events_observetouch"), + "observeNotification": FUNCTION("events.html#events_obversenotification"), + "onKeyDown": FUNCTION("events.html#events_events_onkeydown_keyname_listener"), + "onKeyUp": FUNCTION("events.html#events_events_onkeyup_keyname_listener"), + "onceKeyDown": FUNCTION("events.html#events_events_oncekeydown_keyname_listener"), + "onceKeyUp": FUNCTION("events.html#events_events_oncekeyup_keyname_listener"), + "onToast": FUNCTION("events.html#events_toast"), + "onNotification": FUNCTION("events.html#events_notification"), + "removeAllKeyDownListeners": FUNCTION("events.html#events_events_removeallkeydownlisteners_keyname"), + "removeAllKeyUpListeners": FUNCTION("events.html#events_events_removeallkeyuplisteners_keyname"), + "onTouch": FUNCTION("events.html#events_events_ontouch_listener"), + "removeAllTouchListeners": FUNCTION("events.html#events_events_removealltouchlisteners"), + "getTouchEventTimeout": FUNCTION("events.html#events_events_gettoucheventtimeout"), + "setTouchEventTimeout": FUNCTION("events.html#events_events_settoucheventtimeout_timeout"), + "on": FUNCTION("events.html#events_eventemitter_on_eventname_listener"), + "once": FUNCTION("events.html#events_eventemitter_once_eventname_listener"), + "emit": FUNCTION("events.html#events_eventemitter_emit_eventname_args"), + "getListeners": FUNCTION(), + "addListener": FUNCTION("events.html#events_eventemitter_addlistener_eventname_listener"), + "eventNames": FUNCTION("events.html#events_eventemitter_eventnames"), + "listenerCount": FUNCTION("events.html#events_eventemitter_listenercount_eventname"), + "listeners": FUNCTION("events.html#events_eventemitter_listeners_eventname"), + "prependListener": FUNCTION("events.html#events_eventemitter_prependlistener_eventname_listener"), + "prependOnceListener": FUNCTION("events.html#events_eventemitter_prependoncelistener_eventname_listener"), + "removeAllListeners": FUNCTION("events.html#events_eventemitter_removealllisteners_eventname"), + "removeListener": FUNCTION("events.html#events_eventemitter_removelistener_eventname_listener"), + "setMaxListeners": FUNCTION("events.html#events_eventemitter_setmaxlisteners_n"), + "getMaxListeners": FUNCTION("events.html#events_eventemitter_getmaxlisteners"), + "defaultMaxListeners": FUNCTION("events.html#events_eventemitter_defaultmaxlisteners"), + __url__: "events.html" + }; + var files = { + "open": FUNCTION(), + "isFile": FUNCTION("files.html#files_files_isfile_path"), + "isDir": FUNCTION("files.html#files_files_isdir_path"), + "isEmptyDir": FUNCTION("files.html#files_files_isemptydir_path"), + "join": FUNCTION("files.html#files_files_join_parent_child"), + "create": FUNCTION("files.html#files_files_create_path"), + "createIfNotExists": FUNCTION("files.html#files_files_createifnotexists_path"), + "exists": FUNCTION("files.html#files_files_exists_path"), + "ensureDir": FUNCTION("files.html#files_files_ensuredir_path"), + "read": FUNCTION("files.html#files_files_read_path_encoding_utf_8"), + "write": FUNCTION("files.html#files_files_write_path_text_encoding_utf_8"), + "copy": FUNCTION("files.html#files_files_copy_frompath_topath"), + "move": FUNCTION("files.html#files_files_move_frompath_topath"), + "rename": FUNCTION("files.html#files_files_rename_path_newname"), + "renameWithoutExtension": FUNCTION("files.html#files_files_renamewithoutextension_path_newname"), + "getName": FUNCTION("files.html#files_files_getname_path"), + "getExtension": FUNCTION("files.html#files_files_getextension_path"), + "getNameWithoutExtension": FUNCTION("files.html#files_files_getnamewithoutextension_path"), + "remove": FUNCTION("files.html#files_files_remove_path"), + "removeDir": FUNCTION("files.html#files_files_removedir_path"), + "getSdcardPath": FUNCTION("files.html#files_files_getsdcardpath"), + "listDir": FUNCTION("files.html#files_files_listdir_path_filter"), + __url__: "files.html" + }; + var timers = { + "setTimeout": FUNCTION("timers.html#timers_settimeout_callback_delay_args"), + "clearTimeout": FUNCTION("timers.html#timers_cleartimeout_id"), + "setInterval": FUNCTION("timers.html#timers_setinterval_callback_delay_args"), + "clearInterval": FUNCTION("timers.html#timers_clearinterval_id"), + "setImmediate": FUNCTION("timers.html#timers_setimmediate_callback_args"), + "clearImmediate": FUNCTION("timers.html#timers_clearimmediate_id") + }; + var globals = { + "app": app, + "automator": automator, + "console": console, + "dialogs": dialogs, + "events": events, + "images": images, + "files": files, + "timers": timers, + "ui": {}, + + "click": FUNCTION(), + "longClick": FUNCTION(), + "press": FUNCTION(), + "swipe": FUNCTION(), + "gesture": FUNCTION(), + "gestures": FUNCTION(), + "gestureAsync": FUNCTION(), + "gesturesAsync": FUNCTION(), + "scrollDown": FUNCTION(), + "scrollUp": FUNCTION(), + "input": FUNCTION(), + "setText": FUNCTION(), + + "print": FUNCTION(), + "log": FUNCTION(), + "err": FUNCTION(), + "openConsole": FUNCTION(), + "clearConsole": FUNCTION(), + + "rawInput": FUNCTION(), + "input": FUNCTION(), + "alert": FUNCTION(), + "confirm": FUNCTION(), + "prompt": FUNCTION(), + + "requestScreenCapture": FUNCTION(), + "captureScreen": FUNCTION(), + "findColor": FUNCTION(), + "findColorInRegion": FUNCTION(), + "findColorEquals": FUNCTION(), + + "open": FUNCTION(), + + "id": FUNCTION(), + "idContains": FUNCTION(), + "idStartsWith": FUNCTION(), + "idEndsWith": FUNCTION(), + "idMatches": FUNCTION(), + "text": FUNCTION(), + "textContains": FUNCTION(), + "textStartsWith": FUNCTION(), + "textEndsWith": FUNCTION(), + "textMatches": FUNCTION(), + "desc": FUNCTION(), + "descContains": FUNCTION(), + "descStartsWith": FUNCTION(), + "descEndsWith": FUNCTION(), + "descMatches": FUNCTION(), + "className": FUNCTION(), + "classNameContains": FUNCTION(), + "classNameStartsWith": FUNCTION(), + "classNameEndsWith": FUNCTION(), + "classNameMatches": FUNCTION(), + "packageName": FUNCTION(), + "packageNameContains": FUNCTION(), + "packageNameStartsWith": FUNCTION(), + "packageNameEndsWith": FUNCTION(), + "packageNameMatches": FUNCTION(), + "bounds": FUNCTION(), + "boundsInside": FUNCTION(), + "boundsContains": FUNCTION(), + "drawingOrder": FUNCTION(), + "checkable": FUNCTION(), + "checked": FUNCTION(), + "focusable": FUNCTION(), + "focused": FUNCTION(), + "visibleToUser": FUNCTION(), + "accessibilityFocused": FUNCTION(), + "selected": FUNCTION(), + "clickable": FUNCTION(), + "longClickable": FUNCTION(), + "enabled": FUNCTION(), + "password": FUNCTION(), + "scrollable": FUNCTION(), + "editable": FUNCTION(), + "contentInvalid": FUNCTION(), + "contextClickable": FUNCTION(), + "multiLine": FUNCTION(), + "dismissable": FUNCTION(), + "checkable": FUNCTION(), + "checked": FUNCTION(), + "focusable": FUNCTION(), + "focused": FUNCTION(), + "visibleToUser": FUNCTION(), + "accessibilityFocused": FUNCTION(), + "selected": FUNCTION(), + "clickable": FUNCTION(), + "longClickable": FUNCTION(), + "enabled": FUNCTION(), + "password": FUNCTION(), + "scrollable": FUNCTION(), + "editable": FUNCTION(), + "contentInvalid": FUNCTION(), + "contextClickable": FUNCTION(), + "multiLine": FUNCTION(), + "dismissable": FUNCTION(), + + "SetScreenMetrics": FUNCTION(), + "Tap": FUNCTION(), + "Swipe": FUNCTION(), + "Screencap": FUNCTION(), + "KeyCode": FUNCTION(), + "Home": FUNCTION(), + "Back": FUNCTION(), + "Power": FUNCTION(), + "Up": FUNCTION(), + "Down": FUNCTION(), + "Left": FUNCTION(), + "Right": FUNCTION(), + "OK": FUNCTION(), + "VolumeUp": FUNCTION(), + "VolumeDown": FUNCTION(), + "Menu": FUNCTION(), + "Camera": FUNCTION(), + "Text": FUNCTION(), + + "loop": FUNCTION(), + "setTimeout": FUNCTION(), + "clearTimeout": FUNCTION(), + "setInterval": FUNCTION(), + "clearInterval": FUNCTION(), + "setImmediate": FUNCTION(), + "clearImmediate": FUNCTION(), + + "newInjectableWebClient": FUNCTION(), + "newInjectableWebView": FUNCTION(), + + "toast": FUNCTION(), + "toastLog": FUNCTION(), + "sleep": FUNCTION(), + "isStopped": FUNCTION(), + "notStopped": FUNCTION(), + "exit": FUNCTION(), + "setClip": FUNCTION(), + "getClip": FUNCTION(), + "currentPackage": FUNCTION(), + "currentActivity": FUNCTION(), + "waitForActivity": FUNCTION(), + "waitForPackage": FUNCTION(), + "setScreenMetrics": FUNCTION(), + + "context": {}, + "activity": {} + }; + return globals; } diff --git a/app/src/main/assets/editor/codemirror/addon/autojs/autojs-hint.js b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-hint.js new file mode 100644 index 00000000..293db28b --- /dev/null +++ b/app/src/main/assets/editor/codemirror/addon/autojs/autojs-hint.js @@ -0,0 +1,171 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + var c = getCompletions(token, context, keywords, options); + return {list: c.list, + urls: c.urls, + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function forAllProps(obj, callback) { + for (var name in obj) { + var value = obj[name]; + callback(name, value.__url__); + } + return; + //unreachable + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (var name in obj) callback(name) + } else { + for (var o = obj; o; o = Object.getPrototypeOf(o)) + Object.getOwnPropertyNames(o).forEach(callback) + } + } + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + var urls = []; + function maybeAdd(str, url) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) { + found.push(str); + urls.push(url); + } + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd) + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return { + list: found, + urls: urls + } + } + +}); diff --git a/app/src/main/assets/editor/codemirror/addon/hint/show-hint.js b/app/src/main/assets/editor/codemirror/addon/hint/show-hint.js index afe67546..474aa833 100644 --- a/app/src/main/assets/editor/codemirror/addon/hint/show-hint.js +++ b/app/src/main/assets/editor/codemirror/addon/hint/show-hint.js @@ -128,9 +128,10 @@ if (picked && data.list.length == 1) { this.pick(data, 0); } else { + console.log("data:", data); //Modified By Stardust if(typeof __bridge__ != 'undefined'){ - __bridge__.updateCodeCompletion(data.from.line, data.from.ch, data.to.line, data.to.ch, data.list); + __bridge__.updateCodeCompletion(data.from.line, data.from.ch, data.to.line, data.to.ch, data.list, data.urls); }else{ this.widget = new Widget(this, data); } diff --git a/app/src/main/assets/editor/index.html b/app/src/main/assets/editor/index.html index 5a7e440f..76b23ba5 100644 --- a/app/src/main/assets/editor/index.html +++ b/app/src/main/assets/editor/index.html @@ -31,7 +31,7 @@ - + @@ -55,16 +55,6 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/assets/help/catalogue.json b/app/src/main/assets/help/catalogue.json deleted file mode 100644 index b4d48365..00000000 --- a/app/src/main/assets/help/catalogue.json +++ /dev/null @@ -1,310 +0,0 @@ -{ - "main": [ - { - "title": "简介与说明", - "type": "markdown", - "path":"documentation" - }, - { - "title": "如何阅读本文档", - "type": "markdown", - "path":"documentation" - }, - { - "title": "ECMAScript教程", - "type": "catalogue" - }, - { - "title": "常见问题", - "type": "markdown", - "path":"documentation" - }, - { - "title": "自动操作函数", - "type": "markdown", - "path":"documentation" - }, - { - "title": "一般常用函数", - "type": "markdown", - "path":"documentation" - }, - { - "title": "选择器", - "type": "markdown", - "path":"documentation" - }, - { - "title": "Android7.0以上点按与手势模拟", - "type": "markdown", - "path": "documentation" - }, - { - "title": "图片与图色处理", - "type": "markdown", - "path":"documentation" - }, - { - "title": "控制台与输出", - "type": "markdown", - "path":"documentation" - }, - { - "title": "事件与按键、触摸监听", - "type": "markdown", - "path":"documentation" - }, - { - "title": "定时器", - "type": "markdown", - "path":"documentation" - }, - { - "title": "shell命令", - "type": "markdown", - "path":"documentation" - }, - { - "title": "需要Root权限的自动操作函数", - "type": "markdown", - "path":"documentation" - }, - { - "title": "需要Root权限的触摸与多点触摸", - "type": "markdown", - "path":"documentation" - }, - { - "title": "UI(用户界面)", - "type": "markdown", - "path":"documentation" - }, - { - "title": "文件读写", - "type": "markdown", - "path":"documentation" - }, - { - "title": "应用", - "type": "markdown", - "path":"documentation" - }, - { - "title": "脚本引擎", - "type": "markdown", - "path":"documentation" - }, - { - "title": "模块与第三方jar", - "type": "markdown", - "path":"documentation" - }, - { - "title": "调用Java API", - "type": "markdown", - "path":"documentation" - } - ], - "ECMAScript教程": [ - { - "title": "基础", - "type": "catalogue" - }, - { - "title": "运算符", - "type": "catalogue" - }, - { - "title": "语句", - "type": "catalogue" - }, - { - "title": "函数", - "type": "catalogue" - }, - { - "title": "对象", - "type": "catalogue" - } - ], - "基础": [ - { - "title": "语法", - "type":"html", - "path":"w3c" - }, - { - "title": "变量", - "type":"html", - "path":"w3c" - }, - { - "title": "关键字", - "type":"html", - "path":"w3c" - }, - { - "title": "保留字", - "type":"html", - "path":"w3c" - }, - { - "title": "值", - "type":"html", - "path":"w3c" - }, - { - "title": "原始类型", - "type":"html", - "path":"w3c" - }, - { - "title": "类型转换", - "type":"html", - "path":"w3c" - }, - { - "title": "引用类型", - "type":"html", - "path":"w3c" - } - ], - "运算符": [ - { - "title": "一元运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "位运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "逻辑运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "乘性运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "加性运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "关系运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "等性运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "条件运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "赋值运算符", - "type":"html", - "path":"w3c" - }, - { - "title": "逗号运算符", - "type":"html", - "path":"w3c" - } - ], - "语句": [ - { - "title": "if 语句", - "type":"html", - "path":"w3c" - }, - { - "title": "迭代语句", - "type":"html", - "path":"w3c" - }, - { - "title": "标签语句", - "type":"html", - "path":"w3c" - }, - { - "title": "break 和 continue 语句", - "type":"html", - "path":"w3c" - }, - { - "title": "with 语句", - "type":"html", - "path":"w3c" - }, - { - "title": "switch 语句", - "type":"html", - "path":"w3c" - } - ], - "函数": [ - { - "title": "函数概述", - "type":"html", - "path":"w3c" - }, - { - "title": "arguments 对象", - "type":"html", - "path":"w3c" - }, - { - "title": "Function 对象(类)", - "type":"html", - "path":"w3c" - }, - { - "title": "闭包(closure)", - "type":"html", - "path":"w3c" - } - ], - "对象": [ - { - "title": "面向对象技术", - "type":"html", - "path":"w3c" - }, - { - "title": "对象应用", - "type":"html", - "path":"w3c" - }, - { - "title": "对象类型", - "type":"html", - "path":"w3c" - }, - { - "title": "对象作用域", - "type":"html", - "path":"w3c" - }, - { - "title": "定义类或对象", - "type":"html", - "path":"w3c" - }, - { - "title": "修改对象", - "type":"html", - "path":"w3c" - } - ] -} \ No newline at end of file diff --git a/app/src/main/assets/help/developerguide/如何写自动操作脚本.md b/app/src/main/assets/help/developerguide/如何写自动操作脚本.md deleted file mode 100644 index d52505e1..00000000 --- a/app/src/main/assets/help/developerguide/如何写自动操作脚本.md +++ /dev/null @@ -1,16 +0,0 @@ - -## 控件 - -对于一般软件而言,其界面是由控件组成的。 - -一段文本、一张图片、一个列表都是一个控件(widget),文本用文本控件(TextView)显示,图片用图片控件(ImageView)显示。 - -此外还有一类特殊的控件,其本身不显示内容,而是作为其他控件的"容器"使用,决定在他里面的控件的位置和排放。这类控件称为"布局"(layout)。 - -常见的布局有线性布局(LinearLayout), 相对布局(RelativeLayout), 帧布局(FrameLayout), 表格布局(GridLayout)等。 - -例如线性布局,在他里面的控件是线性(垂直或平行)地摆放的。比如一个水平的线性布局,里面依次有一个文本控件和一个图片控件,那么显示时图片将会在文本的右边。 - -## 控件的属性 - -打开悬浮窗,找到 diff --git a/app/src/main/assets/help/documentation/Android7.0以上点按与手势模拟.md b/app/src/main/assets/help/documentation/Android7.0以上点按与手势模拟.md deleted file mode 100644 index e1152c94..00000000 --- a/app/src/main/assets/help/documentation/Android7.0以上点按与手势模拟.md +++ /dev/null @@ -1,79 +0,0 @@ -在Android7.0及以上,可以不需要root权限做到任意坐标的点击,滑动和手势模拟,并且比使用root权限的延迟更短。 - -**注意以下命令只有Android7.0及以上才有效** - -### click(x, y) -* x \ 要点击的坐标的x值 -* y \ 要点击的坐标的y值 - -模拟点击坐标(x, y),并返回是否点击成功。只有在点击执行完成后脚本才继续执行。 - -一般而言,只有点击过程(大约150毫秒)中被其他事件中断(例如用户自行点击)才会点击失败。 - -> 可以在开发者选项中启用指针位置来查看坐标 - -### longClick(x, y) - -* x \ 要长按的坐标的x值 -* y \ 要长按的坐标的y值 - -模拟长按坐标(x, y), 并 返回是否成功。只有在长按执行完成(大约600毫秒)时脚本才会继续执行。 - -一般而言,只有长按过程中被其他事件中断(例如用户自行点击)才会长按失败。 - -### press(x, y, duration) - -* x \ 要按住的坐标的x值 -* y \ 要按住的坐标的y值 -* duration \ 按住时长,单位毫秒 - -模拟按住坐标(x, y), 并返回是否成功。只有按住操作执行完成时脚本才会继续执行。 - -如果按住时间过短,那么会被系统认为是点击;如果时长超过500毫秒,则认为是长按。 - -一般而言,只有按住过程中被其他事件中断才会操作失败。 - -### swipe(x1, y1, x2, y2, duration) - -* x1 \ 滑动的起始坐标的x值 -* y1 \ 滑动的起始坐标的y值 -* x2 \ 滑动的结束坐标的x值 -* y2 \ 滑动的结束坐标的y值 -* duration \ 滑动时长,单位毫秒 - -模拟从坐标(x1, y1)滑动到坐标(x2, y2),并返回是否成功。只有滑动操作执行完成时脚本才会继续执行。 - -一般而言,只有滑动过程中被其他事件中断才会滑动失败。 - -### gesture(duration, \[x1, y1\], \[x2, y2\], ...) - -* duration \ 手势的时长 -* \[x, y\] \ 手势滑动路径的一系列坐标 - -模拟手势操作。例如`gesture(1000, [0, 0], [500, 500], [500, 1000])`为模拟一个从(0, 0)到(500, 500)到(500, 100)的手势操作,时长为2秒。 - -### gestures(\[delay, duration, \[x1, y1\], \[x2, y2\], ...], \[delay, duration, \[x3, y3\], \[x4, y4\], ...\], ...) - -同时模拟多个手势。每个手势的参数为\[delay, duration, 坐标\], delay为延迟多久(毫秒)才执行该手势;duration为手势执行时长;坐标为手势经过的点的坐标。其中delay参数可以省略,默认为0。 - -参见示例。 - - -### setScreenMetrics(width, height) - -* width \ 屏幕宽度,单位像素 -* height <\Number\> 屏幕高度,单位像素 - -设置脚本坐标点击所适合的屏幕宽高。如果脚本运行时,屏幕宽度不一致会自动放缩坐标。 - -例如在1920*1080的设备中,某个操作的代码为 -``` -setScreenMetrics(1080, 1920); -click(800, 200); -longClick(300, 500); -``` -那么在其他设备上AutoJs会自动放缩坐标以便脚本仍然有效。 - - - - diff --git a/app/src/main/assets/help/documentation/shell命令.md b/app/src/main/assets/help/documentation/shell命令.md deleted file mode 100644 index 4c65520b..00000000 --- a/app/src/main/assets/help/documentation/shell命令.md +++ /dev/null @@ -1,385 +0,0 @@ -shell命令是通过shell函数运行的命令。等同于"adb shell"。shell函数的参数如下: -## shell(cmd[, root]) -* cmd \ 要执行的命令 -* root \ 是否以root权限运行,默认为false。 -返回运行一个执行结果。该返回值一般不会用到,其属性如下: - * code \ 返回码。执行成功时为0,失败时为非0的数字。 - * result \ 运行结果。 - * error \ 运行的错误信息。例如执行需要root权限的命令但没有授予root权限会返回错误信息"Permission denied"。 - -示例(强制停止微信) : -``` -var result = shell("am force-stop com.tencent.mm", true); -log(result); -openConsole(); -if(result.code == 0){ - toast("执行成功"); -}else{ - toast("执行失败!请到控制台查看错误信息"); -} -``` - -以下关于shell命令的资料来自[AndroidStudio用户指南:Shell命令](https://developer.android.com/studio/command-line/adb.html#shellcommands)。 - -目录: -* [am命令](#am命令) -* [intent参数的规范](#intent参数的规范) -* [应用包名](#应用包名) -* [pm命令](#pm命令) -* [其他命令](#其他命令) -* [Shell类](#Shell类) - -## am命令 - -am命令即Activity Manager命令,用于管理应用程序活动、服务等。 - -**以下命令均以"am "开头,例如"shell(\"am start -p com.tencent.mm\");"(启动微信)** - -### start [options] intent -启动 intent 指定的 Activity(应用程序活动)。 -请参阅 [intent 参数的规范](#intent参数的规范)。 - -选项包括: - -* -D:启用调试。 -* -W:等待启动完成。 -* --start-profiler file:启动分析器并将结果发送到 file。 -* -P file:类似于 --start-profiler,但当应用进入空闲状态时分析停止。 -* -R count:重复 Activity 启动 count 次数。在每次重复前,将完成顶部 Activity。 -* -S:启动 Activity 前强行停止目标应用。 -* --opengl-trace:启用 OpenGL 函数的跟踪。 -* --user user_id | current:指定要作为哪个用户运行;如果未指定,则作为当前用户运行。 - -### startservice [options] intent -启动 intent 指定的 Service(服务)。 -请参阅 [intent 参数的规范](#intent参数的规范)。 -选项包括: - -* --user user_id | current:指定要作为哪个用户运行;如果未指定,则作为当前用户运行。 - -### force-stop package -强行停止与 package([应用包名](#应用包名))关联的所有应用。 - -### kill [options] package -终止与 package([应用包名](#应用包名))关联的所有进程。此命令仅终止可安全终止且不会影响用户体验的进程。 -选项包括: - -* --user user_id | all | current:指定将终止其进程的用户;如果未指定,则终止所有用户的进程。 - -### kill-all -终止所有后台进程。 - -### broadcast [options] intent -发出广播 intent。 -请参阅 [intent 参数的规范](#intent参数的规范)。 - -选项包括: - -* [--user user_id | all | current]:指定要发送到的用户;如果未指定,则发送到所有用户。 - -### instrument [options] component -使用 Instrumentation 实例启动监控。通常,目标 component 是表单 test_package/runner_class。 -选项包括: - -* -r:输出原始结果(否则对 report_key_streamresult 进行解码)。与 [-e perf true] 结合使用以生成性能测量的原始输出。 -* -e name value:将参数 name 设为 value。对于测试运行器,通用表单为 -e testrunner_flag value[,value...]。 -* -p file:将分析数据写入 file。 -* -w:先等待仪器完成,然后再返回。测试运行器需要使用此选项。 -* --no-window-animation:运行时关闭窗口动画。 -* --user user_id | current:指定仪器在哪个用户中运行;如果未指定,则在当前用户中运行。 -* profile start process file 启动 process 的分析器,将结果写入 file。 -* profile stop process 停止 process 的分析器。 - -### dumpheap [options] process file -转储 process 的堆,写入 file。 - -选项包括: - -* --user [user_id|current]:提供进程名称时,指定要转储的进程用户;如果未指定,则使用当前用户。 -* -n:转储原生堆,而非托管堆。 -* set-debug-app [options] package 将应用 package 设为调试。 - -选项包括: - -* -w:应用启动时等待调试程序。 -* --persistent:保留此值。 -* clear-debug-app 使用 set-debug-app 清除以前针对调试用途设置的软件包。 - -### monitor [options] 启动对崩溃或 ANR 的监控。 -选项包括: - -* --gdb:在崩溃/ANR 时在给定端口上启动 gdbserv。 -### screen-compat {on|off} package -控制 package 的屏幕兼容性模式。 - -### display-size [reset|widthxheight] -替换模拟器/设备显示尺寸。此命令对于在不同尺寸的屏幕上测试您的应用非常有用,它支持使用大屏设备模仿小屏幕分辨率(反之亦然)。 -示例: -``` -shell("am display-size 1280x800", true); - -``` -### display-density dpi -替换模拟器/设备显示密度。此命令对于在不同密度的屏幕上测试您的应用非常有用,它支持使用低密度屏幕在高密度环境环境上进行测试(反之亦然)。 -示例: -``` -shell("am display-density 480", true); -``` -### to-uri intent -将给定的 intent 规范以 URI 的形式输出。 -请参阅 [intent 参数的规范](#intent参数的规范)。 - -### to-intent-uri intent -将给定的 intent 规范以 intent:URI 的形式输出。 -请参阅 intent 参数的规范。 - -### intent参数的规范 -对于采用 intent 参数的 am 命令,您可以使用以下选项指定 intent: - -* -a action -指定 intent 操作,如“android.intent.action.VIEW”。此指定只能声明一次。 -* -d data_uri -指定 intent 数据 URI,如“content://contacts/people/1”。此指定只能声明一次。 -* -t mime_type -指定 intent MIME 类型,如“image/png”。此指定只能声明一次。 -* -c category -指定 intent 类别,如“android.intent.category.APP_CONTACTS”。 -* -n component -指定带有软件包名称前缀的组件名称以创建显式 intent,如“com.example.app/.ExampleActivity”。 -* -f flags -将标志添加到 setFlags() 支持的 intent。 -* --esn extra_key -添加一个 null extra。URI intent 不支持此选项。 -* -e|--es extra_key extra_string_value -添加字符串数据作为键值对。 -* --ez extra_key extra_boolean_value -添加布尔型数据作为键值对。 -* --ei extra_key extra_int_value -添加整数型数据作为键值对。 -* --el extra_key extra_long_value -添加长整型数据作为键值对。 -* --ef extra_key extra_float_value -添加浮点型数据作为键值对。 -* --eu extra_key extra_uri_value -添加 URI 数据作为键值对。 -* --ecn extra_key extra_component_name_value -添加组件名称,将其作为 ComponentName 对象进行转换和传递。 -* --eia extra_key extra_int_value[,extra_int_value...] -添加整数数组。 -* --ela extra_key extra_long_value[,extra_long_value...] -添加长整型数组。 -* --efa extra_key extra_float_value[,extra_float_value...] -添加浮点型数组。 -* --grant-read-uri-permission -包含标志 FLAG_GRANT_READ_URI_PERMISSION。 -* --grant-write-uri-permission -包含标志 FLAG_GRANT_WRITE_URI_PERMISSION。 -* --debug-log-resolution -包含标志 FLAG_DEBUG_LOG_RESOLUTION。 -* --exclude-stopped-packages -包含标志 FLAG_EXCLUDE_STOPPED_PACKAGES。 -* --include-stopped-packages -包含标志 FLAG_INCLUDE_STOPPED_PACKAGES。 -* --activity-brought-to-front -包含标志 FLAG_ACTIVITY_BROUGHT_TO_FRONT。 -* --activity-clear-top -包含标志 FLAG_ACTIVITY_CLEAR_TOP。 -* --activity-clear-when-task-reset -包含标志 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET。 -* --activity-exclude-from-recents -包含标志 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS。 -* --activity-launched-from-history -包含标志 FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY。 -* --activity-multiple-task -包含标志 FLAG_ACTIVITY_MULTIPLE_TASK。 -* --activity-no-animation -包含标志 FLAG_ACTIVITY_NO_ANIMATION。 -* --activity-no-history -包含标志 FLAG_ACTIVITY_NO_HISTORY。 -* --activity-no-user-action -包含标志 FLAG_ACTIVITY_NO_USER_ACTION。 -* --activity-previous-is-top -包含标志 FLAG_ACTIVITY_PREVIOUS_IS_TOP。 -* --activity-reorder-to-front -包含标志 FLAG_ACTIVITY_REORDER_TO_FRONT。 -* --activity-reset-task-if-needed -包含标志 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。 -* --activity-single-top -包含标志 FLAG_ACTIVITY_SINGLE_TOP。 -* --activity-clear-task -包含标志 FLAG_ACTIVITY_CLEAR_TASK。 -* --activity-task-on-home -包含标志 FLAG_ACTIVITY_TASK_ON_HOME。 -* --receiver-registered-only -包含标志 FLAG_RECEIVER_REGISTERED_ONLY。 -* --receiver-replace-pending -包含标志 FLAG_RECEIVER_REPLACE_PENDING。 -* --selector -需要使用 -d 和 -t 选项以设置 intent 数据和类型。 -#### URI component package -如果不受上述某一选项的限制,您可以直接指定 URI、软件包名称和组件名称。当参数不受限制时,如果参数包含一个“:”(冒号),则此工具假定参数是一个 URI;如果参数包含一个“/”(正斜杠),则此工具假定参数是一个组件名称;否则,此工具假定参数是一个软件包名称。 - -## 应用包名 -所谓应用包名,是唯一确定应用的标识。例如微信的包名是"com.tencent.mm", QQ的包名是"com.tencent.mobileqq"。 -要获取一个应用的包名,可以通过函数`getPackageName(appName)`获取。参见帮助->其他一般函数。 - - -## pm命令 - -pm命令用于管理应用程序,例如卸载应用、冻结应用等。 -**以下命令均以"pm "开头,例如"shell(\"pm disable com.tencent.mm\");"(冻结微信)** - -### list packages [options] filter -输出所有软件包,或者,仅输出包名称包含 filter 中的文本的软件包。 -选项: - -* -f:查看它们的关联文件。 -* -d:进行过滤以仅显示已停用的软件包。 -* -e:进行过滤以仅显示已启用的软件包。 -* -s:进行过滤以仅显示系统软件包。 -* -3:进行过滤以仅显示第三方软件包。 -* -i:查看软件包的安装程序。 -* -u:也包括卸载的软件包。 -* --user user_id:要查询的用户空间。 - -### list permission-groups -输出所有已知的权限组。 -### list permissions [options] group -输出所有已知权限,或者,仅输出 group 中的权限。 -选项: - -* -g:按组加以组织。 -* -f:输出所有信息。 -* -s:简短摘要。 -* -d:仅列出危险权限。 -* -u:仅列出用户将看到的权限。 - -### list instrumentation [options] -列出所有测试软件包。 -选项: - -* -f:列出用于测试软件包的 APK 文件。 -* target_package:列出仅用于此应用的测试软件包。 - -### list features -输出系统的所有功能。 -### list libraries -输出当前设备支持的所有库。 -### list users -输出系统上的所有用户。 -### path package -输出给定 package 的 APK 的路径。 -### install [options] path -将软件包(通过 path 指定)安装到系统。 -选项: - -* -l:安装具有转发锁定功能的软件包。 -* -r:重新安装现有应用,保留其数据。 -* -t:允许安装测试 APK。 -* -i installer_package_name:指定安装程序软件包名称。 -* -s:在共享的大容量存储(如 sdcard)上安装软件包。 -* -f:在内部系统内存上安装软件包。 -* -d:允许版本代码降级。 -* -g:授予应用清单文件中列出的所有权限。 - -### uninstall [options] package - -从系统中卸载软件包。 -选项: - -* -k:移除软件包后保留数据和缓存目录。 -### clear package -删除与软件包关联的所有数据。 - -### enable package_or_component -启用给定软件包或组件(作为“package/class”写入)。 - -### disable package_or_component -停用给定软件包或组件(作为“package/class”写入)。 - -### disable-user [options] package_or_component - -选项: - -* --user user_id:要停用的用户。 -### grant package_name permission -向应用授予权限。在运行 Android 6.0(API 级别 23)及更高版本的设备上,可以是应用清单中声明的任何权限。在运行 Android 5.1(API 级别 22)和更低版本的设备上,必须是应用定义的可选权限。 - -### revoke package_name permission -从应用中撤销权限。在运行 Android 6.0(API 级别 23)及更高版本的设备上,可以是应用清单中声明的任何权限。在运行 Android 5.1(API 级别 22)和更低版本的设备上,必须是应用定义的可选权限。 - -### set-install-location location -更改默认安装位置。位置值: -* 0:自动—让系统决定最佳位置。 -* 1:内部—安装在内部设备存储上。 -* 2:外部—安装在外部介质上。 - -> 注:此命令仅用于调试目的;使用此命令会导致应用中断和其他意外行为。 - -### get-install-location -返回当前安装位置。返回值: -* 0 [auto]:让系统决定最佳位置。 -* 1 [internal]:安装在内部设备存储上 -* 2 [external]:安装在外部介质上 - -### set-permission-enforced permission [true|false] -指定是否应强制执行给定的权限。 - -### trim-caches desired_free_space -减少缓存文件以达到给定的可用空间。 - -### create-user user_name -使用给定的 user_name 创建新用户,输出新用户的标识符。 - -### remove-user user_id -移除具有给定的 user_id 的用户,删除与该用户关联的所有数据。 - -### get-max-users -输出设备支持的最大用户数。 - -## 其他命令 - -### 进行屏幕截图 -screencap 命令是一个用于对设备显示屏进行屏幕截图的 shell 实用程序。在 shell 中,此语法为: -``` -screencap filename -``` - -例如: -``` -$ shell("screencap /sdcard/screen.png"); -``` - -### 列表文件 -``` -ls filepath -``` -例如: -``` -log(shell("ls /system/bin")); -``` - -## Shell类 - -当需要连续执行很多命令时,每条命令都需要申请Root权限,执行时间会大大增加。这时可以使用Shell类。 -### new Shell(root = false) -* root \ 是否以root权限执行。默认为false。 - -Shell类的构造函数。 - -### Shell.exec(cmd) -* cmd \ 要执行的命令 - -该命令没有返回值。 - -执行命令cmd,例如: -``` -var sh = new Shell(true); -sh.exec("rm -f /sdcard/1.txt"); //删除SD卡上的1.txt文件 -``` - -### Shell.exit() -退出Shell。调用该函数后再执行的命令无效。 - - -除以上命令之外, Shell也包含自动操作的命令,例如Shell.Tap,参见《需要Root权限的自动操作函数》。 \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/一般常用函数.md b/app/src/main/assets/help/documentation/一般常用函数.md deleted file mode 100644 index 4ab50a8c..00000000 --- a/app/src/main/assets/help/documentation/一般常用函数.md +++ /dev/null @@ -1,85 +0,0 @@ -### sleep(\[n\]) -* n \ 毫秒数 - -暂停运行n**毫秒**的时间。1秒等于1000毫秒。 -如果不加参数n,则会一直暂停,通常用于有事件监听的脚本中使用。 - -### launchPackage(packageName) -* packageName \ 应用包名。参见《Shell命令:应用包名》章节。 - -运行包名为packageName的应用主界面(Launcher)。例如,打开微信为: -``` -launchPackage("com.tencent.mm"); -``` - -### launchApp(appName) -* appName \ 应用名称 - -运行应用名称为appName的应用主界面。当有应用名称相同时只运行其中某一个。 -例如,打开微信为: -``` -launchApp("微信"); -``` - -### currentPackage() -返回最近一次监测到的正在运行的应用的包名,一般可以认为就是当前正在运行的应用的包名。 - -### currentActivity() -返回最近一次监测到的正在运行的Activity的名称,一般可以认为就是当前正在运行的Activity的名称。 - -### getPackageName(appName) -* appName \ 应用名称 - -获取应用的包名。例如getPackageName("QQ")为"com.tencent.mobileqq"。如果有相同名称的应用,只返回其中某一个的包名。如果不存在这个名称的应用,会返回空字符串。 - -### getAppName(packageName) -* packageName \ 应用包名 - -返回对应包名的应用的名称。如果应用不存在,返回null。 - -### openAppSetting(packageName) -* packageName \ 应用包名 - -打开某个应用的应用详情页,也就是管理应用权限和可以停止其运行的页面。如果应用包名不存在,则返回false;否则返回true。 - -### setClip(text) -* text \ 文本 - -设置剪贴板内容。此剪贴板即系统剪贴板,在一般应用的输入框中"粘贴"既可使用。 - -### getClip() - -返回系统剪贴板的内容。 - -### waitForActivity(activity\[, period = 200\]) -* activity Activity名称 -* period 轮询等待间隔(毫秒) - -等待指定的Activity出现。 - - -### waitForPackage(package\[, period = 200\]) -* package 包名 -* period 轮询等待间隔(毫秒) - -等待指定的应用出现。例如`waitForPackage("com.tencent.mm")`为等待当前界面为微信。 - -### isStopped() -当脚本处于应当停止运行的状态时返回true, 否则返回false。 -由于脚本引擎的关系,有时即使强制停止正在运行的脚本也不会生效,此时会出现isStopped()为true但脚本仍在运行的情况。 - -### isRunning() -当脚本处于正在运行的状态时返回true, 否则返回false。 - -### exit() -立即停止脚本运行。 - -### random(min, max) -* min \ 随机数产生的区间下界 -* max \ 随机数产生的区间上界 - -返回一个在\[min...max\]之间的随机数。例如random(0, 2)可能产生0, 1, 2. - -### random() - -返回在[0, 1)的随机浮点数。 \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/事件与按键、触摸监听.md b/app/src/main/assets/help/documentation/事件与按键、触摸监听.md deleted file mode 100644 index 2495692b..00000000 --- a/app/src/main/assets/help/documentation/事件与按键、触摸监听.md +++ /dev/null @@ -1,414 +0,0 @@ - -目录: -* [events](#events) -* [EventEmitter](#EventEmitter) -* [KeyEvent](#KeyEvent) - -# events - -events也是一个\[EventEmitter\](#EventEmitter),可以使用EventEmitter的所有函数,这里只介绍其自身的函数。 - -``` -events.observeKey(); -events.onKeyDown("volume_up", function(event){ - toast("音量上键被按下了"); -}); -events.onKeyDown("menu", function(event){ - toast("菜单键被按下了"); -}); - -//后面的语句不会再执行了 -``` - - -## events.emitter() - -返回一个新的EventEmitter。 - -## events.observeKey() - -启用按键监听,例如音量键、Home键。 - -在安卓4.3以上才能使用。 - -## events.onKeyDown(keyName, listener) -* keyName \ 要监听的按键名称 -* listener \ 参数为一个[KeyEvent](#KeyEvent) - -注册一个按键监听函数,当有keyName对应的按键被按下会调用该函数。按键名称主要包括: -* volume_up 音量上键 -* volume_down 音量下键 -* home 主屏幕键 -* back 返回键 -* menu 菜单键 - -## events.onKeyUp(keyName, listener) -* keyName \ 要监听的按键名称 -* listener \ 参数为一个[KeyEvent](#KeyEvent) - - -注册一个按键监听函数,当有keyName对应的按键弹起时会调用该函数。 - -## events.onceKeyDown(keyName, listener) -* keyName \ 要监听的按键名称 -* listener \ 参数为一个[KeyEvent](#KeyEvent) - -注册一个按键监听函数,当有keyName对应的按键被按下时会调用该函数,之后会注销该按键监听。也就是listener只会被调用一次。 - -## events.onceKeyUp(keyName, listener) -* keyName \ 要监听的按键名称 -* listener \ 参数为一个[KeyEvent](#KeyEvent) - -注册一个按键监听函数,当有keyName对应的按键弹起时会调用该函数,之后会注销该按键监听。也就是listener只会被调用一次。 - -## events.removeAllKeyDownListeners(keyName) -* keyName \ 按键名称 - -删除该按键的KeyDown事件的所有监听。 - -## events.removeAllKeyUpListeners(keyName) -* keyName \ 按键名称 - -删除该按键的KeyUp事件的所有监听。 - -## events.observeTouch() - -启用屏幕触摸监听。(需要root权限) - -## events.setTouchEventTimeout(timeout) -* timeout \ 两个触摸事件的最小间隔。单位毫秒。默认为10毫秒。 - -设置两个触摸事件分发的最小时间间隔。 - -例如间隔为10毫秒的话,前一个触摸事件发生并被注册的监听器处理后,至少要过10毫秒才能分发和处理下一个触摸事件,这10毫秒之间的触摸将会被忽略。 - -## events.getTouchEventTimeout() - -返回触摸事件的最小时间间隔。 - -## events.onTouch(listener) -* listener \ 参数为Point的函数 - -注册一个触摸监听函数。相当于`on("touch", listener)`。 - -例如: -``` -events.observeTouch(); -events.onTouch(function(p){ - log(p.x + ", " + p.y); -}); -events.loop(); -``` - -## events.removeAllTouchListeners() - -删除所有事件监听函数。 - -## 事件: 'key' -* keyCode \ 键值 -* event \ 事件 - -当有按键被按下或弹起时会触发该事件。 -``` -"auto"; -events.observeKey(); -events.on("key", function(keyCode, event){ - //处理按键事件 -}); -events.loop(); -``` -其中监听器的参数KeyCode包括: -* KeyEvent.KEYCODE_HOME 主页键 -* KeyEvent.KEYCODE_BACK 返回键 -* KeyEvent.KEYCODE_MENU 菜单键 -* KeyEvent.KEYCODE_VOLUME_UP 音量上键 -* KeyEvent.KEYCODE_VOLUME_DOWN 音量下键 - -## 事件: 'key_down' -* keyCode \ 键值 -* event \ 事件 - -当有按键被按下时会触发该事件。 -``` -"auto"; -events.observeKey(); -events.on("key_down", function(keyCode, event){ - //处理按键按下事件 -}); -events.loop(); -``` - -## 事件: 'key_up' -* keyCode \ 键值 -* event \ 事件 - -当有按键弹起时会触发该事件。 -``` -"auto"; -events.observeKey(); -events.on("key_up", function(keyCode, event){ - //处理按键弹起事件 -}); -events.loop(); -``` - - -## obverseNotification() -开启通知(包括Toast)监听。 -``` -events.obverseNotification(); -events.onNotification(function(notification){ - log(notification.getText()); -}); -events.onToast(function(toast){ - log(toast.getText()); -}); -``` - -## 事件: 'toast' -* toast \ - * getText() 获取Toast的文本内容 - * getPackageName() 获取发出Toast的应用包名 - -## 事件: 'notification' -* notification \ 通知 - -``` -events.observeNotification(); -events.on("notification", function(notification){ - log(notification); -}); - -``` - - -# EventEmitter - -## EventEmitter.defaultMaxListeners - -每个事件默认可以注册最多 10 个监听器。 单个 EventEmitter 实例的限制可以使用 emitter.setMaxListeners(n) 方法改变。 所有 EventEmitter 实例的默认值可以使用 EventEmitter.defaultMaxListeners 属性改变。 - -设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有 EventEmitter 实例,包括之前创建的。 因而,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners。 - -注意,与Node.js不同,**这是一个硬性限制**。 EventEmitter 实例不允许添加更多的监听器,监听器超过最大数量时会抛出TooManyListenersException。 -``` -emitter.setMaxListeners(emitter.getMaxListeners() + 1); -emitter.once('event', () => { - // 做些操作 - emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0)); -}); -``` -## EventEmitter.addListener(eventName, listener) -* eventName {any} -* listener {Function} - -emitter.on(eventName, listener) 的别名。 - -## EventEmitter.emit(eventName\[, ...args\]) -* eventName {any} -* args {any} - -按监听器的注册顺序,同步地调用每个注册到名为 eventName 事件的监听器,并传入提供的参数。 - -如果事件有监听器,则返回 true ,否则返回 false。 - -## EventEmitter.eventNames() - -返回一个列出触发器已注册监听器的事件的数组。 数组中的值为字符串或符号。 -``` -const myEE = events.emitter(); -myEE.on('foo', () => {}); -myEE.on('bar', () => {}); - -const sym = Symbol('symbol'); -myEE.on(sym, () => {}); - -console.log(myEE.eventNames()); -// 打印: [ 'foo', 'bar', Symbol(symbol) ] -``` -## EventEmitter.getMaxListeners() - -返回 EventEmitter 当前的最大监听器限制值,该值可以通过 emitter.setMaxListeners(n) 设置或默认为 EventEmitter.defaultMaxListeners。 - -## EventEmitter.listenerCount(eventName) -* eventName {any} 正在被监听的事件名 - -返回正在监听名为 eventName 的事件的监听器的数量。 - -## EventEmitter.listeners(eventName) -* eventName {any} - -返回名为 eventName 的事件的监听器数组的副本。 -``` -server.on('connection', (stream) => { - console.log('someone connected!'); -}); -console.log(util.inspect(server.listeners('connection'))); -// 打印: [ [Function] ] -``` - -## EventEmitter.on(eventName, listener) -* eventName {any} 事件名 -* listener {Function} 回调函数 - -添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。 -``` -server.on('connection', (stream) => { - console.log('有连接!'); -}); -``` -返回一个 EventEmitter 引用,可以链式调用。 - -默认情况下,事件监听器会按照添加的顺序依次调用。 emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头。 -``` -const myEE = events.emitter(); -myEE.on('foo', () => console.log('a')); -myEE.prependListener('foo', () => console.log('b')); -myEE.emit('foo'); -// 打印: -// b -// a -``` - - -## EventEmitter.once(eventName, listener)# -* `eventName` {any} 事件名 -* `listener` {Function} 回调函数 - -添加一个单次 listener 函数到名为 eventName 的事件。 下次触发 eventName 事件时,监听器会被移除,然后调用。 -``` -server.once('connection', (stream) => { - console.log('首次调用!'); -}); -``` -返回一个 EventEmitter 引用,可以链式调用。 - -默认情况下,事件监听器会按照添加的顺序依次调用。 emitter.prependOnceListener() 方法可用于将事件监听器添加到监听器数组的开头。 -``` -const myEE = events.emitter(); -myEE.once('foo', () => console.log('a')); -myEE.prependOnceListener('foo', () => console.log('b')); -myEE.emit('foo'); -// 打印: -// b -// a -``` - -## EventEmitter.prependListener(eventName, listener) -* `eventName` {any} 事件名 -* `listener` {Function} 回调函数 - -添加 listener 函数到名为 eventName 的事件的监听器数组的开头。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。 -``` -server.prependListener('connection', (stream) => { - console.log('有连接!'); -}); -``` -返回一个 EventEmitter 引用,可以链式调用。 - -## EventEmitter.prependOnceListener(eventName, listener) -* `eventName` {any} 事件名 -* `listener` {Function} 回调函数 - -添加一个单次 listener 函数到名为 eventName 的事件的监听器数组的开头。 下次触发 eventName 事件时,监听器会被移除,然后调用。 -``` -server.prependOnceListener('connection', (stream) => { - console.log('首次调用!'); -}); -``` -返回一个 EventEmitter 引用,可以链式调用。 - -## EventEmitter.removeAllListeners(\[eventName\]) -* `eventName` {any} - -移除全部或指定 eventName 的监听器。 - -注意,在代码中移除其他地方添加的监听器是一个不好的做法,尤其是当 EventEmitter 实例是其他组件或模块创建的。 - -返回一个 EventEmitter 引用,可以链式调用。 - -## EventEmitter.removeListener(eventName, listener) -* `eventName` {any} -* `listener` {Function} - -从名为 eventName 的事件的监听器数组中移除指定的 listener。 -``` -const callback = (stream) => { - console.log('有连接!'); -}; -server.on('connection', callback); -// ... -server.removeListener('connection', callback); -``` -removeListener 最多只会从监听器数组里移除一个监听器实例。 如果任何单一的监听器被多次添加到指定 eventName 的监听器数组中,则必须多次调用 removeListener 才能移除每个实例。 - - -注意,一旦一个事件被触发,所有绑定到它的监听器都会按顺序依次触发。 这意味着,在事件触发后、最后一个监听器完成执行前,任何 removeListener() 或 removeAllListeners() 调用都不会从 emit() 中移除它们。 随后的事件会像预期的那样发生。 -``` -const myEmitter = events.emitter(); - -const callbackA = () => { - console.log('A'); - myEmitter.removeListener('event', callbackB); -}; - -const callbackB = () => { - console.log('B'); -}; - -myEmitter.on('event', callbackA); - -myEmitter.on('event', callbackB); - -// callbackA 移除了监听器 callbackB,但它依然会被调用。 -// 触发是内部的监听器数组为 [callbackA, callbackB] -myEmitter.emit('event'); -// 打印: -// A -// B - -// callbackB 被移除了。 -// 内部监听器数组为 [callbackA] -myEmitter.emit('event'); -// 打印: -// A -``` -因为监听器是使用内部数组进行管理的,所以调用它会改变在监听器被移除后注册的任何监听器的位置索引。 虽然这不会影响监听器的调用顺序,但意味着由 emitter.listeners() 方法返回的监听器数组副本需要被重新创建。 - -返回一个 EventEmitter 引用,可以链式调用。 - -## EventEmitter.setMaxListeners(n) -* n {number} - -默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告。 此限制有助于寻找内存泄露。 但是,并不是所有的事件都要被限为 10 个。 emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制。 值设为 Infinity(或 0)表明不限制监听器的数量。 - -返回一个 EventEmitter 引用,可以链式调用。 - -# KeyEvent - -## KeyEvent.getAction() - -返回事件的动作。包括: -* `KeyEvent.ACTION_DOWN` 按下事件 -* `KeyEvent.ACTION_UP` 弹起事件 - -## KeyEvent.getKeyCode() - -返回按键的键值。包括: -* `KeyEvent.KEYCODE_HOME` 主页键 -* `KeyEvent.KEYCODE_BACK` 返回键 -* `KeyEvent.KEYCODE_MENU` 菜单键 -* `KeyEvent.KEYCODE_VOLUME_UP` 音量上键 -* `KeyEvent.KEYCODE_VOLUME_DOWN` 音量下键 - -## KeyEvent.getEventTime() - -返回事件发生的时间戳。返回值的类型是number。 - -## KeyEvent.getDownTime() - -返回最近一次按下事件的时间戳。如果本身是按下事件,则与getEventTime()相同。 - -## KeyEvent.keyCodeToString(keyCode) - -把键值转换为字符串。例如`KEYCODE_HOME`转换为`"KEYCODE_HOME"`。 diff --git a/app/src/main/assets/help/documentation/图片与图色处理.md b/app/src/main/assets/help/documentation/图片与图色处理.md deleted file mode 100644 index 93a53379..00000000 --- a/app/src/main/assets/help/documentation/图片与图色处理.md +++ /dev/null @@ -1,179 +0,0 @@ -目录: -* [截图](#截图) -* [images](#images) -* [colors](#colors) -* [Image](#Image) -* [Point](#Point) - -# 截图 - -截图有关的函数需要安卓5.0以上才支持。 -### requestScreenCapture(\[width, height\]) -* width \ 截图宽度 -* height \ 截图高度 - -向系统申请屏幕截图权限,返回是否请求成功。 - -第一次使用该函数会弹出截图权限请求,建议选择“总是允许”。 - -这个函数只是申请截图权限,并不会真正执行截图,真正的截图函数是[captureScreen](#captureScreen())。 - -不指定参数时默认为屏幕宽高。指定参数时,并不会严格以width和height为截图宽度和高度,而是以和width, height接近的最适合的宽高为截图宽高。例如在1920\*1080屏幕中requestScreenCapture(600, 1000)请求的截图的高度一般是540\*960。 - -如果在第一次权限请求时选择"总是允许", 之后的脚本执行该函数通常耗时200毫秒以内(测试机型:小米6)。 - -建议在本软件界面运行该函数,在其他软件界面运行时容易出现一闪而过的黑屏。 - -### captureScreen() - -截取当前屏幕并返回一个[Image](#Image)对象。该图片的宽高取决于requestScreenCapture所指定的宽高。 - -没有截图权限时执行该函数会抛出SecurityException。 - -该函数耗时一毫秒以内(测试机型:小米6)。因此不必担心截图的速度。图色处理的瓶颈通常在找色部分。 - -### captureScreen(path) -* path \ 截图保存路径 - -截取当前屏幕并以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。 - -# images - -images是图片与图色处理的工具。包括获取图片某点颜色,保存图片,找色等。 - -### images.pixel(image, x, y) -* image \ 图片 -* x \ 要获取的像素的横坐标。坐标系以图片左上角为原点。 -* y \ 要获取的像素的纵坐标。 - -返回图片image在点(x, y)处的像素的ARGB值。 -该值的格式为0xAARRGGBB。也就是,如果`var argb = images.pixel(image, x, y)`,那么可以通过`(argb & 0xFF000000) >> 24`获取透明度,通过`(argb & 0xFF0000) >> 16`获取R值,通过`(argb & 0xFF000000) >> 24`获取G值等,或者通过`colors.alpha(argb)`, `colors.red(argb)`等获取。 - -### images.saveImage(image, path) - -* image \ 图片 -* path \ 路径 - -把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。 - -### images.findColor(image, color, options) -* image \ 图片 -* color \或\ 要寻找的颜色的RGB值。如果是一个整数,则以0xRRGGBB的形式代表RGB值(A通道会被忽略);如果是字符串,则以"#RRGGBB"代表其RGB值。 -* options \ 选项 - -在图片中寻找颜色color。找到时返回找到的点[Point](#Point),找不到时返回null。 -选项包括: -* region \ 找色区域。是一个两个或四个元素的数组。(region\[0\], region\[1\])表示找色区域的左上角;region\[2\]*region\[3\]表示找色区域的宽高。如果只有region只有两个元素,则找色区域为(region\[0\], region\[1\])到屏幕右下角。如果不指定region选项,则找色区域为整张图片。 -* threads \ 指定找色使用的线程数。不能超过16。最适合的线程数取决于设备。默认线程数为2。 -* algorithm \ 指定颜色匹配算法。包括: - * "equal": 相等匹配,只有与给定颜色color完全相等时才匹配。 - * "diff": 差值匹配。与给定颜色的R、G、B差的绝对值之和小于threshold时匹配。 - * "rgb": rgb欧拉距离相似度。与给定颜色color的rgb欧拉距离小于等于threshold时匹配。 - * "rgb+": 加权rgb欧拉距离匹配([LAB Delta E](https://en.wikipedia.org/wiki/Color_difference))。 - * "hs": hs欧拉距离匹配。hs为HSV空间的色调值。 -* threshold \ 找色时颜色相似度的临界值,范围为0~255(越小越相似,0为颜色相等,255为任何颜色都能匹配)。默认为16。threshold和浮点数相似度(0.0~1.0)的换算为 similarity = (255 - threshold) / 255. - -该函数也可以作为全局函数使用。 - - -### images.findColorInRegion(img, color, x, y\[, width, height, threads, algorithm, threshold\]) - -相当于 -``` -images.findColor(img, color, { - region: [x, y, width, height], - algorithm: algorithm, - threshold: threshold, - threads: threads -}); -``` - -该函数也可以作为全局函数使用。 - -### images.findColorEquals(img, color, x, y, width, height, threads) - -相当于 -``` -images.findColor(img, color, { - region: [x, y, width, height], - algorithm: "equal", - threads: threads -}); -``` - -该函数也可以作为全局函数使用。 - - -### images.detectsColor(image, color, x, y\[, threshold = 16, algorithm = "rgb"\]) -* image \ 图片 -* color \ 要检测的颜色 -* x \ 要检测的位置横坐标 -* y \ 要检测的位置纵坐标 -* threshold \ 颜色相似度临界值,默认为16 -* algorithm \ 颜色匹配算法,默认为rgb欧式距离 - -返回图片image在位置(x, y)处是否匹配到颜色color。有关threshold和algorithm的信息,参考findColor函数。 - -# colors - -colors是颜色处理的工具对象。包含一些常用方法,除了android.graphics.Color的所有方法外,加上toString方法。 - -### colors.toString(color) -* color \ 整数RGB颜色值 - -返回颜色值的字符串,格式为 #AARRGGBB。 - -### colors.red(color) -* color \ 整数RGB颜色值 - -返回颜色color的R通道的值,范围0~255. - -### colors.green(color) -* color \ 整数RGB颜色值 - -返回颜色color的G通道的值,范围0~255. - -### colors.blue(color) -* color \ 整数RGB颜色值 - -返回颜色color的B通道的值,范围0~255. - -### colors.alpha(color) -* color \ 整数RGB颜色值 - -返回颜色color的Alpha通道的值,范围0~255. - -### colors.rgb(red, green, blue) -* red \ 颜色的R通道的值 -* blue \ 颜色的G通道的值 -* green \ 颜色的B通道的值 - -返回这些颜色通道构成的整数颜色值。Alpha通道将是255(不透明)。 - -### colors.argb(alpha, red, green, blue) -* alpha \ 颜色的Alpha通道的值 -* red \ 颜色的R通道的值 -* green \ 颜色的G通道的值 -* blue \ 颜色的B通道的值 - -返回这些颜色通道构成的整数颜色值。 - -# Image - -[captureScreen](#captureScreen()) 返回的对象。 - -### Image.getWidth() - -返回以像素为单位图片宽度。 - -### Image.getHeight() - -返回以像素为单位的图片高度。 - -# Point - -findColor返回的对象。 - -### Point.x -### Point.y - 坐标。 diff --git a/app/src/main/assets/help/documentation/如何阅读本文档.md b/app/src/main/assets/help/documentation/如何阅读本文档.md deleted file mode 100644 index 70b96c0a..00000000 --- a/app/src/main/assets/help/documentation/如何阅读本文档.md +++ /dev/null @@ -1,30 +0,0 @@ -先看一个例子,下面是《自动操作函数》的章节中input函数的部分说明。 -### input(\[i, \]text) -* i \ 表示要输入的为第i + 1个输入框 -* text \ 要输入的文本 - -input表示函数名,括号内为函数的参数。下面是参数列表,"\"表示该参数类型为数值,"\"表示该参数类型为字符串。 - -例如`input(1, "啦啦啦")`,执行这个语句会在屏幕上的第2个输入框处输入"啦啦啦“。 - -方括号\[ \]表示参数为可选参数。也就是说,可以省略i直接调用input。例如`input("嘿嘿嘿")`,按照文档,这个语句会在屏幕上所有输入框输入"嘿嘿嘿"。 - -调用有可选参数的函数时请**不要**写上方括号。 - -我们再看第二个例子。图片和图色处理中detectsColor函数的部分说明。 - -### images.detectsColor(image, color, x, y\[, threshold = 16, algorithm = "rgb"\]) -* image \ 图片 -* color \ 要检测的颜色 -* x \ 要检测的位置横坐标 -* y \ 要检测的位置纵坐标 -* threshold \ 颜色相似度临界值,默认为16 -* algorithm \ 颜色匹配算法,默认为rgb欧式距离 - -同样地,"\[, threshold = 16, algorithm = "rgb"\]"为可选参数,并且,等于号=后面的值为参数的默认值。也就是如果不指定该参数,则该参数将会为这个值。 - -例如 `images.detectsColor(captureScreen(), "#112233", 100, 200)` 相当于 `images.detectsColor(captureScreen(), "#112233", 100, 200, 16, "rgb")`,而`images.detectsColor(captureScreen(), "#112233", 100, 200, 64)` 相当于`images.detectsColor(captureScreen(), "#112233", 100, 200, 64, "rgb")` 。 - -调用有可选参数及默认值的函数时请**不要**写上方括号和等于号。 - -好了先这样吧 :-\) diff --git a/app/src/main/assets/help/documentation/定时器.md b/app/src/main/assets/help/documentation/定时器.md deleted file mode 100644 index c4f11548..00000000 --- a/app/src/main/assets/help/documentation/定时器.md +++ /dev/null @@ -1,50 +0,0 @@ -timer 模块暴露了一个全局的 API,用于在某个未来时间段调用调度函数。 因为定时器函数是全局的,所以使用该 API 无需调用 timer.*** - -Auto.js 中的计时器函数实现了与 Web 浏览器提供的定时器类似的 API,除了它使用了一个不同的内部实现,它是基于 Android Looper-Handler机制构建的。其实现机制与Node.js比较相似。 - -### setImmediate(callback\[, ...args\]) -* callback \ 在 Auto.js 循环的当前回合结束时要调用的函数。 -* ...args \ 当调用 callback 时要传入的可选参数。 - -预定立即执行的 callback,它是在 I/O 事件的回调之后被触发。 返回一个用于 clearImmediate() 的 id。 - -当多次调用 setImmediate() 时,callback 函数会按照它们被创建的顺序依次执行。 每次事件循环迭代都会处理整个回调队列。 如果一个立即定时器是被一个正在执行的回调排入队列的,则该定时器直到下一次事件循环迭代才会被触发。 - -### setInterval(callback, delay\[, ...args\]) -* callback \ 当定时器到点时要调用的函数。 -* delay \ 调用 callback 之前要等待的毫秒数。 -* ...args \ 当调用 callback 时要传入的可选参数。 - -预定每隔 delay 毫秒重复执行的 callback。 返回一个用于 clearInterval() 的 id。 - -当 delay 小于 0 时,delay 会被设为 0。 - -### setTimeout(callback, delay\[, ...args\]) -* callback \ 当定时器到点时要调用的函数。 -* delay \ 调用 callback 之前要等待的毫秒数。 -* ...args \ 当调用 callback 时要传入的可选参数。 - -预定在 delay 毫秒之后执行的单次 callback。 返回一个用于 clearTimeout() 的 id。 - -callback 可能不会精确地在 delay 毫秒被调用。 Auto.js 不能保证回调被触发的确切时间,也不能保证它们的顺序。 回调会在尽可能接近所指定的时间上调用。 - -当 delay 小于 0 时,delay 会被设为 0。 - -setImmediate()、setInterval() 和 setTimeout() 方法每次都会返回表示预定的计时器的id。 它们可用于取消定时器并防止触发。 - - -### clearImmediate(id) -* id \ 一个 setImmediate() 返回的 id。 - -取消一个由 setImmediate() 创建的 Immediate 对象。 - -### clearInterval(id) -* id \ 一个 setInterval() 返回的 id。 - -取消一个由 setInterval() 创建的 Timeout 对象。 - -### clearTimeout(id) -* id \ 一个 setTimeout() 返回的 id。 - -取消一个由 setTimeout() 创建的 Timeout 对象。 - diff --git a/app/src/main/assets/help/documentation/常见问题.md b/app/src/main/assets/help/documentation/常见问题.md deleted file mode 100644 index 1612c1bb..00000000 --- a/app/src/main/assets/help/documentation/常见问题.md +++ /dev/null @@ -1,50 +0,0 @@ -目录 -* [没有root权限是否支持游戏](#没有root权限是否支持游戏) -* [如何重复做某些操作n次](#如何重复做某些操作n次) -* [如何循环做某些操作](#如何循环做某些操作) -* [某些有文字的按键点击无效怎么办](#某些有文字的按键点击无效怎么办) -* [如何点击图标按钮](#如何点击图标按钮) -* [如何支持Tasker调用](#如何支持Tasker调用) - -### 没有root权限是否支持游戏 - -**游戏需要root权限!!!** -**游戏需要root权限!!!** -**游戏需要root权限!!!** -100%的游戏在没有root权限的情况下都不支持。 -不管是录制脚本还是运行脚本,在没有root权限的情况下都无法做到,在游戏界面不使用root权限录制脚本录制出来的是空白的。 - -### 如何重复做某些操作n次 - -使用循环语句实现实现。例如每个1秒执行一个操作,总共执行20次的代码如下: -``` -for(var i = 1; i <= 20; i++){ - //这里写要执行的操作 - sleep(1000); -} -``` - -### 如何循环做某些操作 - -使用while(true)语句实现。例如QQ无限发送消息的脚本如下: -``` -while(true){ - input("测试"); - click("发送"); -} -``` - -### 某些有文字的按键点击无效怎么办 - -例如QQ下方的"联系人"按钮,用click("联系人")是无效的。这是因为这些按钮上的文字并不是真正的文字,而是一个图标。参见[如何点击图标按钮](#如何点击图标按钮)。 - -### 如何点击图标按钮 - -有以下几种方法: -* 录制脚本 -* 通过图标在屏幕上的位置来点击。要获取图标在屏幕上的位置,可以开启悬浮窗,选择布局范围查看,之后点击要点击的图标,在弹出的窗口中的"bounds"一栏即图标在屏幕上的区域。例如: -* 通过id, desc等选择器来定位图片 - -### 如何支持Tasker调用 - -新建任务时选择文件,点击浏览找到要运行的脚本文件,在MimeType处填入application/x-javascript。 \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/应用.md b/app/src/main/assets/help/documentation/应用.md deleted file mode 100644 index 651d6703..00000000 --- a/app/src/main/assets/help/documentation/应用.md +++ /dev/null @@ -1,46 +0,0 @@ - -### app.intent(intent) -* intent \ 一个表示Intent对象,其属性可以包括: - * action \ 这个Intent的Action,比如"android.intent.action.SEND" - * type \ 这个Intent的MimeType,比如"text/plain" - * data \ 这个Intent的Data(Uri),可以是文件路径或者Url等。 - * category \ 这个Intent的Category的字符串数组。 - * packageName \ 目标包名 - * className \ 目标Activity或Service等组件的名称 - * extras \ 以键值对构成的这个Intent的Extras。 - -返回用intent对象构造的android.content.Intent对象。 - -如果你看了一脸懵逼,请百度[安卓Intent](https://www.baidu.com/s?wd=android%20Intent)。 - -### app.startActivity(intent) -* intent \ 与app.intent函数的参数一样的intent对象。 - -相当于context.startActivity(intent)。 - - -### app.sendBroadcast(intent) -* intent \ 与app.intent函数的参数一样的intent对象。 - -相当于context.sendBroadcast(intent)。 - -### app.viewFile(path) -* path \ 文件路径 - -用其他应用查看文件。 - -### app.editFile(path) -* path \ 文件路径 - -用其他应用编辑文件。 - -### app.uninstall(packageName) -* packageName \ 应用包名 - -卸载应用。 - -### app.openUrl(url) -* url \ 网站的Url - -用浏览器打开网站url。 - diff --git a/app/src/main/assets/help/documentation/控制台与输出.md b/app/src/main/assets/help/documentation/控制台与输出.md deleted file mode 100644 index 515a6bf7..00000000 --- a/app/src/main/assets/help/documentation/控制台与输出.md +++ /dev/null @@ -1,56 +0,0 @@ -控制台通常用来输出一些调试信息和运算结果。 - -### openConsole() -### console.show() - -显示控制台。 -### clearConsole() -### console.clear() - -清空控制台。 - -### log(text) -### console.log(text) - -* text \ | \ 要打印到控制台的信息 - -在控制台中输出文本text并换行,例如`log("Hello world");`。当text是一个对象时则会转换String以后再输出。 - -### print(text) - -在控制台中输出文本text。 - -### err(error) -### console.error(error) -* error \ | \ - -在控制台中输出错误信息,以红色字体显示,例如: -``` -try{ - //do something -}catch(e){ - err("错误"); - err(e); - openConsole(); -} -``` - -### toast(message) -* message \ | \ 要显示的信息 - -以气泡显示信息message几秒。(具体时间取决于安卓系统) - -### toastLog(message) -* message \ | \ 要显示的信息 - -相当于`toast(message);log(message)`。 - -### console.assert(value, message) -* value \ 要断言的布尔值 -* message \ value为false时要输出的信息 - -断言。如果value为false则输出message并停止脚本运行。 - -### console.input(data\[, ...args\]) - -### console.rawInput(data\[, ...args\]) diff --git a/app/src/main/assets/help/documentation/文件读写.md b/app/src/main/assets/help/documentation/文件读写.md deleted file mode 100644 index 9ee50b29..00000000 --- a/app/src/main/assets/help/documentation/文件读写.md +++ /dev/null @@ -1,198 +0,0 @@ - -### open(path\[, mode = "r", encoding = "utf-8", bufferSize = 8192\]) -* path \ 文件路径,例如"/sdcard/1.txt"。 -* mode \ 文件打开模式,包括: - * "r": 只读模式。该模式下只能对文件执行**文本**读取操作。 - * "w": 只写模式。该模式下只能对文件执行**文本**覆盖写入操作。 - * "a": 附加模式。该模式下将会把写入的文本附加到文件末尾。 - 目前暂不支持二进制模式,随机读写模式。 -* encoding \ 字符编码。 -* bufferSize \ 文件读写的缓冲区大小。 - -打开一个文件。根据打开模式返回不同的文件对象。包括: -* "r": 返回一个ReadableTextFile对象。 -* "w", "a": 返回一个WritableTextFile对象。 - -对于"w"模式,如果文件并不存在,则会创建一个,已存在则会清空该文件内容;其他模式文件不存在会抛出FileNotFoundException。 - -# files - -文件处理的工具对象。 - -### files.isFile(path) -* path \ 路径 - -返回路径path是否是文件。 - -### files.isDir(path) -* path \ 路径 - -返回路径path是否是文件夹。 - -### files.isEmptyDir(path) -* path \ 路径 - -返回文件夹path是否为空文件夹。如果该路径并非文件夹,则直接返回false。 - -### files.join(parent, child) -* parent \ 父目录路径 -* child \ 子路径 - -连接两个路径并返回,例如`files.join("/sdcard/", "1.txt")`返回"/sdcard/1.txt"。 - -### files.create(path) -* path \ 路径 - -创建一个文件并返回是否创建成功。 - -### files.createIfNotExists(path) -* path \ 路径 - -创建一个文件并返回是否创建成功。 - -### files.exists(path) -* path \ 路径 - -返回在路径path处的文件是否存在。 - -### files.ensureDir(path) -* path \ 路径 - -确保路径path所在的文件夹存在。 - -例如对于路径"/sdcard/Download/ABC/1.txt",如果/Download/文件夹不存在,则会先创建Download,再创建ABC文件夹。 - -### files.read(path\[, encoding = "utf-8"\]) -* path \ 路径 -* encoding \ 字符编码 - -读取文件path的所有内容并返回。 - -### files.write(path, text\[, encoding = "utf-8"\]) -* path \ 路径 -* text \ 要写入的文本内容 -* encoding \ 字符编码 - -把text写入到文件path中。如果文件存在则覆盖,不存在则创建。 - -### files.copy(fromPath, toPath) -* fromPath \ 要复制的原文件路径 -* toPath \ 复制到的文件路径 - -复制文件。例如`files.copy("/sdcard/1.txt", "/sdcard/Download/1.txt")`。 - -### files.move(fromPath, toPath) - -移动文件,返回是否移动成功。例如`files.rename("/sdcard/1.txt", "/sdcard/Download/1.txt")`会把1.txt文件从sd卡根目录移动到Download文件夹。 - -### files.rename(path, newName) -* path \ 要重命名的原文件路径 -* newName \ 要重命名的新文件名 - -重命名文件,并返回是否重命名成功。例如`files.rename("/sdcard/1.txt", "2.txt")`。 - -### files.renameWithoutExtension(path, newName) -* path \ 要重命名的原文件路径 -* newName \ 要重命名的新文件名 - -重命名文件,不包含拓展名,并返回是否重命名成功。例如`files.rename("/sdcard/1.txt", "2")`会把1.txt重命名为2.txt。 - -### files.getName(path) -* path \ 路径 - -返回文件的文件名。例如`files.getName("/sdcard/1.txt")`返回"1.txt"。 - -### files.getNameWithoutExtension(path) -* path \ 路径 - -返回不含拓展名的文件的文件名。例如`files.getName("/sdcard/1.txt")`返回"1"。 - -### files.getExtension(path) -* path \ 路径 - -返回文件的拓展名。例如`files.getExtension("/sdcard/1.txt")`返回"txt"。 - -### files.remove(path) -* path \ 路径 - -删除文件或**空文件夹**,返回是否删除成功。 - -### files.removeDir(path) -* path \ 路径 -* path \ 路径 - -删除文件夹,如果文件夹不为空,则删除该文件夹的所有内容再删除该文件夹,返回是否全部删除成功。 - -### files.getSdcardPath() - -返回SD卡路径。所谓SD卡,即外部存储器。 - -### files.listDir(path\[, filter\]) -* path \ 路径 -* filter \ 过滤函数。接收一个String参数(文件名),返回一个Boolean值。 - -列出文件夹path下的满足条件的文件和文件夹的名称的数组。如果不加filter参数,则返回所有文件和文件夹。 - -例如,获取sdcard目录下的txt文件为 -``` -var txtFiles = files.listDir("/sdcard/", function(name){ - return name.endsWith(".txt") && files.isFile("/sdcard/" + name); -}); -``` - -# ReadableTextFile - -可读文件对象。 - -### ReadableTextFile.read() - -返回该文件剩余的所有内容的字符串。 - -### ReadableTextFile.read(maxCount) - -* maxCount \ 最大读取的字符数量 - -读取该文件接下来最长为maxCount的字符串并返回。即使文件剩余内容不足maxCount也不会出错。 - -### ReadableTextFile.readline() - -读取一行并返回(不包含换行符)。 - -### ReadableTextFile.readlines() - -读取剩余的所有行,并返回它们按顺序组成的字符串数组。 - -### close() - -关闭该文件。 - -**打开一个文件不再使用时务必关闭** - -# PWritableTextFile - -可写文件对象。 - -### PWritableTextFile.write(text) -* text \ 文本 - -把文本内容text写入到文件中。 - -### PWritableTextFile.writeline(line) -* text \ 文本 - -把文本line写入到文件中并写入一个换行符。 - -### PWritableTextFile.writelines(lines) -* lines \ 字符串数组 - -把很多行写入到文件中.... - -### PWritableTextFile.flush() - -把缓冲区内容输出到文件中。 - -### PWritableTextFile.close() - -关闭文件。同时会被缓冲区内容输出到文件。 - -**打开一个文件写入后,不再使用时务必关闭,否则文件可能会丢失** diff --git a/app/src/main/assets/help/documentation/模块与第三方jar.md b/app/src/main/assets/help/documentation/模块与第三方jar.md deleted file mode 100644 index 251329fe..00000000 --- a/app/src/main/assets/help/documentation/模块与第三方jar.md +++ /dev/null @@ -1,23 +0,0 @@ -### loadJar(path) -* path \ jar文件路径 - -载入jar文件。之后改文件的所有类均可直接使用。这在使用第三方库时十分方便。 - -### require(path) -* path \ js文件的相对路径 - -载入js文件并返回该模块。模块文件应该有module.exports语句指定模块的输出对象。 - -例如test.js: -``` -function sayHello(name){ - print("Hello, " + name); -} -module.exports = sayHello; -``` -同一个目录下的test_module.js: -``` -var sayHello = require("test"); -sayHello("AutoJs"); -``` -运行这个脚本将在控制台输出"Hello, AutoJs" \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/简介与说明.md b/app/src/main/assets/help/documentation/简介与说明.md deleted file mode 100644 index 26e76b3f..00000000 --- a/app/src/main/assets/help/documentation/简介与说明.md +++ /dev/null @@ -1,3 +0,0 @@ -本软件采用JavaScript1.7为脚本语言([ECMA-357 ECMAScript for XML (E4X)](http://www.ecma-international.org/publications/standards/Ecma-357.htm)), 采用[Rhino1.7](https://developer.mozilla.org/zh-CN/docs/Mozilla/Projects/Rhino/Overview)为脚本引擎。因而本软件的语法与JavaScript相同,并允许在脚本中调用Android和Java的库。 - -本软件中的EMCAScript教程的章节全部提取自[W3Cschool](http://www.w3school.com.cn/js/pro_js_syntax.asp),如有侵权请联系软件作者,将立即从软件中删除。 diff --git a/app/src/main/assets/help/documentation/脚本引擎.md b/app/src/main/assets/help/documentation/脚本引擎.md deleted file mode 100644 index 9e5872d6..00000000 --- a/app/src/main/assets/help/documentation/脚本引擎.md +++ /dev/null @@ -1,56 +0,0 @@ -# engines - -engines模块包含了一些与脚本引擎有关的函数,包括运行其他脚本,关闭脚本等。 - -### engines.execScript(name, script\[, config\]) -* name \ 要运行的脚本名称。这个名称和文件名称无关,只是在任务管理中显示的名称。 -* script \ 要运行的脚本内容。 -* config \ 运行配置项 - * delay \ 延迟执行的毫秒数,默认为0 - * loopTimes \ 循环运行次数,默认为1 - * interval \ 循环运行时两次运行之间的时间间隔,默认为0 - * path \ | \ 指定脚本运行的目录。这个路径会用于require时寻找模块文件。 - -在新线程中运行脚本script。返回一个\[ScriptExecution\](#ScriptExecution)对象。 - -### engines.execScriptFile(path, \[config\]) -* path \ 要运行的脚本路径。 -* config \ 运行配置项 - * delay \ 延迟执行的毫秒数,默认为0 - * loopTimes \ 循环运行次数,默认为1 - * interval \ 循环运行时两次运行之间的时间间隔,默认为0 - * path \ | \ 指定脚本运行的目录。这个路径会用于require时寻找模块文件。 - -在新线程中运行脚本文件path。返回一个\[ScriptExecution\](#ScriptExecution)对象。 - -### engines.execAutoFile(path, \[config\]) -* path \ 要运行的录制文件路径。 -* config \ 运行配置项 - * delay \ 延迟执行的毫秒数,默认为0 - * loopTimes \ 循环运行次数,默认为1 - * interval \ 循环运行时两次运行之间的时间间隔,默认为0 - * path \ | \ 指定脚本运行的目录。这个路径会用于require时寻找模块文件。 - -在新线程中运行录制文件path。返回一个\[ScriptExecution\](#ScriptExecution)对象。 - -### engines.stopAll() - -停止所有正在运行的脚本。包括当前脚本自身。 - -### engines.stopAllAndToast() - -停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。 - -### engines.myEngine() - -# ScriptExecution - -执行脚本时返回的对象,可以通过他获取执行的引擎、 - -### ScriptExecution.getEngine() - -### ScriptExecution.getConfig() - -### ScriptExecution.getSource() - -先写到这儿吧:-) \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/自动操作函数.md b/app/src/main/assets/help/documentation/自动操作函数.md deleted file mode 100644 index c22de695..00000000 --- a/app/src/main/assets/help/documentation/自动操作函数.md +++ /dev/null @@ -1,95 +0,0 @@ -**自动操作的函数都需要开启"无障碍服务"才能执行,否则执行到相应函数时脚本会停止运行。** -### auto模式 -如果代码的第一行是 -``` -"auto"; -``` -那么脚本运行前会先确保无障碍操作服务已开启。如果服务没有开启,则尝试用root权限开启服务并继续运行脚本,或没有root权限时停止运行脚本并跳转到服务开启界面。 - -注意,由于这个语句在必须在第一行(包括注释),因此使用起来比较不方便,已经被auto()函数代替。 - -您可以在设置中开启"使用Root权限自动开启自动无障碍服务",从而在运行到相应语句时可以自动开启。 - -### auto(\[mode = "normal"\]) -* mode \ 获取屏幕上控件时所使用的模式,包括: - * normal 正常模式 - * fast 快速模式 - -确保无障碍服务开启,这个函数的行为与在代码第一行加上`"auto";`是一样的。同时可以指定参数mode。 - -fast模式对自动操作的脚本执行速度有一定提高,但可能造成脚本运行不稳定。 - -### click(text[, i]) -* text \ 要点击的区域的文本 -* i \ 如果相同的文本在屏幕中出现多次,则i表示要点击第几个文本 - -返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。 - -该函数可以点击大部分包含文字的按钮。例如微信主界面下方的"微信", "联系人", "发现", "我"的按钮。 -通常与while同时使用以便点击按钮直至成功。例如: -``` -while(!click("扫一扫")); -``` -可选参数i通常不必指定,但当屏幕中出现相同的文字时,例如 -* `click(text, i)` 点击第i个文本text所在的区域,并返回是否点击成功。当不指定时点击所有区域。当前界面没有出现该文本或者该文本所在区域不可点击时返回false。例如`click("发现")`,是点击"发现"。如果要点击"发现"直至点击成功可以用`while(!click("发现"))`。 -> 文本所在区域指的是,从文本处向其父视图寻找,直至发现一个可点击的部件为止。 -### click(left, top, bottom, right) -* left 要点击的长方形区域左边与屏幕左边的像素距离 -* top 要点击的长方形区域上边与屏幕上边的像素距离 -* bottom 要点击的长方形区域下边与屏幕上边的像素距离 -* right 要点击的长方形区域右边与屏幕左边的像素距离 - -**注意,该函数一般只用于录制的脚本中使用,在自己写的代码中使用该函数一般没有作用。** - -当屏幕中并未包含与该区域严格匹配的区域,或者该区域不能点击时返回false,否则返回true。 -有些按钮或者部件是图标而不是文字(例如发送朋友圈的照相机图标以及QQ下方的消息、联系人、动态图标),这时不能通过`click(text[, i])`来点击,只能通过描述图标所在的区域来点击。left, bottom, top, right描述的就是点击的区域。 -至于要定位点击的区域,可以在侧拉菜单开启"点击区域辅助"(或者安卓7.0以上在通知栏点击"修改"添加点击区域辅助快捷设定图标),之后每次点击或长按都会提示这次点击或长按的区域并自动保存,可以在编辑器的右侧拉菜单中插入。 -也可以通过录制脚本会生成类似语句。 - -**以下的longClick、select、scrollUp、scrollDown的参数均与click类似,不再赘述。** - -### longClick -长按 -### select -选择 -### scrollUp -上滑。另外不加参数时`scrollUp();`会寻找"最大"的可滑动的控件上滑,例如微信消息列表等。 -参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如`scrollUp(0);`。 -### scrollDown -下滑。不加参数时与scrollUp类似。 -### input(\[i, \]text) -* i \ 表示要输入的为第i + 1个输入框 -* text \ 要输入的文本 - -返回是否输入成功。当找不到对应的文本框时返回false。 -不加参数i则会在所有输入框都输入text。例如`input("测试")`。 - -### setText(\[i, \]text) -* i \ 表示要输入的为第i + 1个输入框 -* text \ 要输入的文本 - -返回是否输入成功。当找不到对应的文本框时返回false。 -不加参数i则会把所有输入框的文本都置为text。例如`input("测试")`。 -这里的输入文本的意思是,把输入框的文本置为text,而不是在原来的文本上追加。 - - -### back() -模拟按下返回键。返回是否执行成功。 - -### home() -模拟按下Home键。返回是否执行成功。 - -### powerDialog() -弹出电源键菜单。返回是否执行成功。 - -### notifications() -弹出通知栏。返回是否执行成功。 - -### quickSettings() -显示快速设置(下拉通知栏到底)。返回是否执行成功。 - -### recents() -显示最近任务。返回是否执行成功。 - -### splitScreen() -分屏。返回是否执行成功。 diff --git a/app/src/main/assets/help/documentation/调用Java API.md b/app/src/main/assets/help/documentation/调用Java API.md deleted file mode 100644 index 9b73780d..00000000 --- a/app/src/main/assets/help/documentation/调用Java API.md +++ /dev/null @@ -1,162 +0,0 @@ -以下内容来自[Rhino:Scripting Java](https://developer.mozilla.org/zh-CN/docs/Mozilla/Projects/Rhino/Scripting_Java)。 - -这个章节描述了如何在rhino中使用java。使用脚本调用Java有很多用途,它使得我们可以利用Java中现有的库,来帮助我们构建强大的脚本。我们可以通过编写脚本,来对Java程序进行测试。可以通过脚本来进行探索式编程,辅助Java的开发,所谓探索式编程,就是通过快速地编程调用库或API来探索这些库或API可以做什么,显而易见,脚本语言很适合探索式编程。 - -这里注意,ECMA标准并没有包含和Java(或者其他任何对象系统)交互的标准。本文所描述的所有内容,应该被认为是一个扩展。 - -目录: -* [访问Java的包和类](#访问Java的包和类) -* [使用Java的类](#使用Java的类) -* [实现Java接口](#实现Java接口) -* [创建Java数组](#创建Java数组) -* [Java字符串与JavaScript字符串](#Java字符串与JavaScript字符串) -* [Java异常](#Java异常) -* [JavaImporter](#JavaImporter) - -## 访问Java的包和类 - -Java的每段代码都是类的一部分,每一个JAVA类都是包的一部分。在Javascript中,脚本不属于任何package。我们可以访问Java包中的类么? - -Rhino定义了一个顶层的变量Packages。Packages的所有属性都是Java中顶层的包,比如java和com。比如我们可以访问java包: -``` -Packages.java.util.Vector -``` -还有一种更方便的方式,Rhino定义了一个顶层的变量java,等价于Packages.java。所以上面的例子可以更简介地写成: -``` -java.util.Vector -``` -如果你的脚本需要访问很多的Java类,每次都附带完整的包名会使得编程很麻烦。Rhino提供了一个顶层的方法importPackage,它的功能和Java的import一样。比如,我们可以导入java.io包中的所有类,然后直接通过类名File来访问java.io.File: -``` -importPackage(java.io) -``` -这里importPackage(java.io)使得java.io包中的所有类(例如File)可以在顶层被访问。这和Java中的java.io.*;等价。 - -要注意Java会默认导入java.lang.*,但是Rhino不会。因为JavaScript的顶层对象Boolean、Math、Number、Object和String和java.lang包中同名的类并不相同。因为这种冲突,建议不要用importPackage来导入java.lang包。 - -有一点要注意的,就是Rhino对于指定包名或类名时是如何处理错误的。如果java.Myclass是可访问的,Rhino会试图加载名为java.MyClass的类,如果加载失败,它会假设java.MyClass是一个包名,不会报错。只有在你试图将这个对象当作类使用时,才会报错。 - -## 使用Java的类 - -现在我们可以访问Java类,下一步就是要创建一个对象。方法就和在Java中一样, 用new来创建对象: -``` -new java.util.Date(); -``` -如果我们将创建的对象存放在JavaScript变量中,我们可以调用它的方法: -``` -var f = new java.io.File("test.text"); -log(f.exists()); -log(f.getName()); -``` -静态方法和属性可以直接通过类对象来访问: -``` -log(java.lang.Math.PI); -``` -不像Java,在JavaScript里,方法就是一个对象。它可以被评估,也可以被调用。如果我们去查看这个方法,我们可以看到这个方法所有重载的形式: -``` -log(f.listFiles); -``` -输出: -``` -function listFiles() {/* -java.io.File[] listFiles() -java.io.File[] listFiles(java.io.FilenameFilter) -java.io.File[] listFiles(java.io.FileFilter) -*/} -``` -输出告诉我们,File类有listFiles方法的三种重载:一种不包含参数的,另一种包含一个FilenameFilter类型的参数,第三个包含一个FileFilter类型的参数。所有的方法都返回一个File对象数组。可以观察到Java方法的参数和返回类型在探索式编程中是非常有用的,尤其是在对一个方法的参数和返回对象不确定的时候。 -另一个有助于探索式编程的特性,是可以看到对象中定义的所有方法和属性。用JavaScript的for..in , 我们可以打印这些值: -``` -for (i in f) { log(i) } -``` -注意这里不仅列出了File类中的所有方法,也列出了从基类java.lang.Object中继承的方法,例如wait。这使得我们可以更好地处理那些有复杂继承关系的对象,因为我们可以看到对象中所有可用的方法。 - -Rhino可以通过属性名来方便地访问JavaBean的属性。一个JavaBean的属性foo被方法getFoo和setFoo定义,另外,一个也叫foo的boolean类型的属性,可以被isFoo来定义。比如, 下面的代码实际上调用了File对象的getName和isDirectory方法。 - -## 实现Java接口 - -``` - obj = { run: function () { log("\nrunning"); } }; - r = new java.lang.Runnable(obj); - t = new java.lang.Thread(r); - t.start(); -``` -若一个接口只有一个方法,也可以用直接用函数代替: -``` -t = java.lang.Thread(function () { print("\nrunning"); }); -t.start(); -``` - -## 创建Java数组、 - -Rhino没有提供特定的语法创建Java的数组,只能通过反射来创建。 -``` -a = java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, 2); -b = java.lang.reflect.Array.newInstance(java.lang.String, 5); -``` -之后可以像JavaScript数组一样使用 -``` -a[0] = 'a'; -a[1] = 'b'; -``` - -## Java字符串与JavaScript字符串 - -Java字符串与JavaScript字符串并不等同,但在某种程度上两者可以通用。例如,你可以传递一个JavaScript的字符串给一个需要Java字符串参数的函数。 -``` - javaString = new java.lang.String("Java"); - jsString = "JavaScript"; - log(javaString.length()); - log(jsString.length); -``` -也可以对Java字符串调用了一个在java.lang.String中没有定义的JavaScript方法,例如: -``` -log(javaString.match(/a.*/)); -``` - -## Java异常 - -例如: -``` -try { - java.lang.Class.forName("NonExistingClass"); -} catch (e) { - if (e.javaException instanceof java.lang.ClassNotFoundException) { - print("Class not found"); - } -} -``` -或者 -``` -function classForName(name) { - try { - return java.lang.Class.forName(name); - } catch (e if e.javaException instanceof java.lang.ClassNotFoundException) { - print("Class " + name + " not found"); - } catch (e if e.javaException instanceof java.lang.NullPointerException) { - print("Class name is null"); - } -} - -classForName("NonExistingClass"); -classForName(null); -``` - -## JavaImporter - -``` -var SwingGui = JavaImporter(Packages.javax.swing, - Packages.javax.swing.event, - Packages.javax.swing.border, - java.awt.event, - java.awt.Point, - java.awt.Rectangle, - java.awt.Dimension); -... - -with (SwingGui) { - var mybutton = new JButton(test); - var mypoint = new Point(10, 10); - var myframe = new JFrame(); -... -} -``` \ No newline at end of file diff --git a/app/src/main/assets/help/documentation/选择器.md b/app/src/main/assets/help/documentation/选择器.md deleted file mode 100644 index 8456a8dc..00000000 --- a/app/src/main/assets/help/documentation/选择器.md +++ /dev/null @@ -1,573 +0,0 @@ -目录: -* [简介](#简介) -* [选择器](#选择器) - * [筛选条件](#筛选条件) - * [搜索](#搜索) - * [操作](#操作) -* [控件](#控件) -* [控件集合](#控件集合) - -## 简介 - -选择器是书写稍微复杂的自动操作脚本所必须。使用选择器的一般步骤是: -1. 用各种筛选条件找出想要的控件,如某个文本控件、列表控件、图片控件 -2. 对找出的控件执行想要的操作,如点击、滑动、设置文字、长按 - -问题的关键在于如何找出想要的控件。对于文本控件一般通过他的文字来定位他,图片控件则通过id或者图片描述(desc)。选择器所做的就是提供这些筛选条件并给出筛选结果。 - -选择器提供了更强大的定位界面控件与对其进行操作的功能,可以用他们完成更多的自动操作和提取界面信息。 -选择器通过附加筛选条件,筛选出符合条件的控件或控件集合,之后可以对这些控件这些操作。 -可供选择的筛选条件包括: -* id -* text 文本 -* desc 描述(Content-Description) -* className 类名 -* packageName 包名 -* bounds 在屏幕上的范围 -* drawingOrder 绘制顺序 -* 各种属性,主要包括: - * clickable 可点击 - * longClickable 可长按 - * checkable 可勾选 - * checked 被勾选 - * scrollable 可滑动 - * selected 被选择 - * editable 可编辑 - * visibleToUser 可见 - * enabled 已启用 - -要对选择器所确定的筛选条件,对屏幕上的控件进行筛选,调用方法find(), findOne(), untilFind()。其中find(), untilFind()返回控件的集合,findOne()返回一个控件。untilFind和FindOne函数会一直寻找直到屏幕上出现满足条件的控件为止。 -一个完整的选择器示例如下: -``` -var emoj = id("name").packageName("com.tencent.mobileqq").clickable() - .className("ImageView").drawingOrder(5).findOne(); -emoj.click(); -``` -上述代码是找到QQ聊天界面下面的表情按钮(第5个按钮)并点击。也可以简化为: -``` -id("name").packageName("com.tencent.mobileqq").clickable() - .className("ImageView").click(); -``` - -这段代码意思是,找出id为"name", 包名为"com.tentcent.mobileqq",类名为ImageView的所有可点击控件,对他们执行点击动作。 - -最后的click()函数相当于untilFind().click()。也就是如果只需要在找到控件以后立即进行操作,只需要调用相应的操作函数,而不需要先调用find等函数等到控件再操作。 -要获取屏幕上的控件的信息(例如id, text, desc, bounds等),可以开启悬浮窗,使用界面层次查看和界面范围查看。 - -选择器部分内容如果有安卓开发经验会更容易掌握。 - -# 选择器 - -## 筛选条件 - -### id(resId) -* resId \ 控件的id,以"包名:id/"开头,例如"com.tencent.mm:id/send_btn"。也可以不指定包名,这时会以当前正在运行的应用的包名来补全id。例如id("send_btn"),在QQ界面想当于id("com.tencent.mobileqq:id/send_btn")。 - -附加id严格匹配筛选条件。 - -控件的id属性通常是可以用来确定控件的唯一标识,如果一个控件有id,那么使用id来找到他是最好的方法。要查看屏幕上的控件的id,可以开启悬浮窗并使用界面工具,点击相应控件即可查看。若查看到的控件id为null, 表示该控件没有id。另外,在列表中会出现多个控件的id相同的情况。例如微信的联系人列表,每个头像的id都是一样的。此时不能用id来唯一确定控件。 - -在QQ界面经常会出现多个id为"name"的控件,在微信上则每个版本的id都会变化。对于这些软件而言比较难用id定位控件。 - -### idContains(str) -* str \ id要包含的字符串 - -附加控件id包含字符串str的筛选条件。 - -### idStartsWith(prefix) -* prefix \ id前缀 - -附加id需要以prefix开头的筛选条件。 - -### idEndsWith(suffix) -* suffix \ id后缀 - -附加id需要以suffix结束的筛选条件。 - -### idMatches(String) -* String \ id要满足的正则表达式 - -附加id需要满足正则表达式。有关正则表达式,可以查看[菜鸟教程](http://www.runoob.com/Stringp/Stringp-example.html)。 - -这里的正则表达式是Java的正则表达式,不能直接使用JavaScript的正则表达式。 -``` -idMatches("[a-zA-Z]+") -``` - -### text(str) -* str \ 控件文本 - -附加控件文本等于字符串str的筛选条件。 - -控件的text(文本)属性是控件上的显示的文字,例如微信左上角的"微信"文本。对于图片或者其他控件通常text属性为null。 - -### textContains(str) - -* str \ 要包含的字符串 - -附加控件文本需要以prefix开头的筛选条件。 - -### textStartsWith(prefix) - -* prefix \ 前缀 - -附加控件文本需要以prefix开头的筛选条件。 - -### textEndsWith(suffix) -* suffix \ 后缀 - -附加控件文本需要以suffix结束的筛选条件。 - -### textMatches(str) -* String \ 要满足的正则表达式 - -附加控件文本需要满足正则表达式的条件。 - -### desc(str) -* str \ 控件描述 - -附加控件描述等于字符串str的筛选条件。 - -控件的desc(描述,全称为Content-Description)属性是对一个控件的描述,例如网易云音乐右上角的放大镜图标的描述为搜索。要查看一个控件的描述,同样地可以借助悬浮窗查看。 - -desc属性同样是定位控件的利器。 - -### descContains(str) - -* str \ 要包含的字符串 - -附加控件描述需要以prefix开头的筛选条件。 - -### descStartsWith(prefix) - -* prefix \ 前缀 - -附加控件描述需要以prefix开头的筛选条件。 - -### descEndsWith(suffix) -* suffix \ 后缀 - -附加控件描述需要以suffix结束的筛选条件。 - -### descMatches(str) -* String \ 要满足的正则表达式 - -附加控件描述需要满足正则表达式的条件。 - -### className(str) -* str \ 控件类名 - -附加控件类名等于字符串str的筛选条件。 - -控件的className属性是一个控件的具体类型,例如图片控件通常为ImageView,文本控件通常为TextView, 输入框通常为EditText。(若一个控件是在android.widget包里的,那么android.widget可以省略。但除此之外的其他控件必须是类的全名,例如"com.stardust.theme.ThemeColorImageView")。 - -### classNameContains(str) - -* str \ 要包含的字符串 - -附加控件类名需要以prefix开头的筛选条件。 - -### classNameStartsWith(prefix) - -* prefix \ 前缀 - -附加控件类名需要以prefix开头的筛选条件。 - -### classNameEndsWith(suffix) -* suffix \ 后缀 - -附加控件类名需要以suffix结束的筛选条件。 - -### classNameMatches(str) -* String \ 要满足的正则表达式 - -附加控件类名需要满足正则表达式的条件。 - -### packageName(str) -* str \ 包名 - -附加包名等于字符串str的筛选条件。 - -packageName属性也即控件所属的应用的包名(参见《shell命令:应用包名》),通常用来保证当前运行的应用是想要的应用。 - -### packageNameContains(str) - -* str \ 要包含的字符串 - -附加包名需要以prefix开头的筛选条件。 - -### packageNameStartsWith(prefix) - -* prefix \ 前缀 - -附加包名需要以prefix开头的筛选条件。 - -### packageNameEndsWith(suffix) -* suffix \ 后缀 - -附加包名需要以suffix结束的筛选条件。 - -### packageNameMatches(str) -* String \ 要满足的正则表达式 - -附加包名需要满足正则表达式的条件。 - -### bounds(l, t, r, b) -* l, t, r, b 用来定位控件在屏幕上的范围的四个整数 - - -### boundsInside(l, t, r, b) - -### boundsContains(l, t, r, b) - -### drawingOrder(order) -* order \ 控件在父视图中的绘制顺序,在一些 - -### checkable(\[b = true\]) -* b \ 表示控件是否可勾选, 默认为true - -附加控件是否可勾选的条件。可勾选指的是,例如QQ和微信发送图片时图片的勾选。 - -### selected(\[b = true\]) -* b \ 表示控件是否被选中,默认为true - -附加控件是否被选中的条件。被选中指的是,例如QQ聊天界面点击下方的表情按钮时,会出现自己收藏的表情,这时表情按钮便处于选中状态。 - -### clickable(\[b = true\]) -* b \ 表示控件是否可点击, 默认为true - -附加控件是否可点击的条件。但并非所有clickable为false的控件都真的不能点击,这取决于控件的实现。因而要确定一个控件的clickable属性,可以开启悬浮窗工具。 - -### longClickable(\[b = true\]) -* b \ 表示控件是否可长按, 默认为true - -附加控件是否可长按的条件。 - -### enabled(\[b = true\]) -* b \ 表示控件是否已启用, 默认为true - -附加控件是否已启用的条件。大多数控件都是启用的状态,处于“禁用”状态通常是灰色并且不可点击。 - -### scrollable(\[b = true\]) -* b \ 表示控件是否可滑动, 默认为true - -附加控件是否可滑动的条件。 - -### editable(\[b = true\]) -* b \ 表示控件是否可编辑, 默认为true - -附加控件是否可编辑的条件。一般来说可编辑的控件为输入框(EditText)。 - -### contentInvalid(\[b = true\]) -* b \ 表示控件是否是contentInvalid, 默认为true - -我也不知道是什么,下次再补充吧。 - -### contextClickable(\[b = true\]) -* b \ 表示控件是否是contextClickable, 默认为true - -我也不知道是什么,下次再补充吧。 - -### multiLine(\[b = true\]) -* b \ 表示文本或输入框控件是否是多行显示的, 默认为true - -附加控件是否文本或输入框控件是否是多行显示的条件。 - -## 搜索 - -### findOne() -根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到屏幕上出现满足条件的一个控件为止,并返回该控件。如果找不到控件,当屏幕内容发生变化时会重新寻找,直至找到。参见[控件](#控件)。 - -### find() -根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,找到所有满足条件的控件集合并返回。这个搜索只进行一次,并不保证一直会找到,因而会出现返回的控件集合为空的情况。参见[控件集合](#控件集合)。 - -可以通过empty()或nonEmpty()函数判断找到的是否为空。例如: -``` -var c = className("AbsListView").find(); -if(c.empty()){ - toast("找到啦"); -}else{ - toast("没找到╭(╯^╰)╮"); -} -``` - -### untilFind() -根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到找到至少一个满足条件的控件为止,并返回所有满足条件的控件集合。参见[控件集合](#控件集合)。 - -### exists() -判断屏幕上是否存在控件符合选择器所确定的条件。例如要判断某个文本出现就执行某个动作,可以用: -``` -if(text("嘿嘿嘿").exists()){ - //嘿嘿嘿 -} -``` - -### waitFor() -等待屏幕上出现符合条件的控件。 -``` -text("嘿嘿嘿").waitFor(); -``` - - -## 操作 - -### click() -找到所有符合条件的控件并点击。相当于untilFind().click()。参见[click](#UiCollection.click())。 - -### longClick() -找到所有符合条件的控件并长按。相当于untilFind().longClick()。参见[longClick](#UiCollection.longClick())。 - -### copy() -找到所有符合条件的控件并复制其内容,只对文本框或输入框控件有文字选中时有效。相当于untilFind().copy()。参见[copy](#UiCollection.copy())。 - -### paste() -找到所有符合条件的控件并粘贴,只对输入框控件有效。相当于untilFind().paste()。参见[paste](#UiCollection.paste())。 - -### select() -找到所有符合条件的控件并选中。相当于untilFind().select()。参见[select](#UiCollection.select())。 - -### cut() -找到所有符合条件的控件并剪切其内容,只对文本框或输入框控件有文字选中时有效。相当于untilFind().cut()。参见[cut](#UiCollection.cut())。 - -### collapse() -找到所有符合条件的控件并折叠。相当于untilFind().collapse()。参见[collapse](#UiCollection.collapse())。 - -### expand() -找到所有符合条件的控件并展开。相当于untilFind().expand()。参见[expand](#UiCollection.expand())。 - -### show() -找到所有符合条件的控件并使其出现在屏幕上。相当于untilFind().show()。参见[show](#UiCollection.show())。 - -### scrollForward() -找到所有符合条件的控件并向前滑。相当于untilFind().scrollForward()。参见[scrollForward](#UiCollection.scrollForward())。 -向前滑指的是,对于左右滑动的控件向右滑,上下滑动的控件向下滑。 - -### scrollBackward() -找到所有符合条件的控件并向后滑。相当于untilFind().scrollBackward()。参见[scrollBackward](#UiCollection.scrollBackward())。 -向后滑指的是,对于左右滑动的控件向左滑,上下滑动的控件向上滑。 - -### scrollUp() -找到所有符合条件的控件并向上滑。相当于untilFind().scrollUp()。参见[scrollUp](#UiCollection.scrollUp())。 - -### scrollDown() -找到所有符合条件的控件并向下滑。相当于untilFind().scrollDown()。参见[scrollDown](#UiCollection.scrollDown())。 - -### scrollLeft() -找到所有符合条件的控件并向左滑。相当于untilFind().scrollLeft()。参见[scrollLeft](#UiCollection.scrollLeft())。 - -### scrollRight() -找到所有符合条件的控件并向右滑。相当于untilFind().scrollRight()。参见[scrollRight](#UiCollection.scrollRight())。 - -### contextClick() -\\\\文档缺失 - -### setSelection(start, end) -* start \ 文字选中开始位置 -* end \ 文字选中结束位置 - -找到所有符合条件的控件并设置文字选中区域,只对文本控件和输入框有效。相当于untilFind().setSelection()。参见[setSelection](#UiCollection.setSelection)。 - -### setText(text) -* text \ 要设置的文本 -找到所有符合条件的控件并设置文字,只对输入框有效。相当于untilFind().setText()。参见[setText](#UiCollection.setText)。 - -# 控件集合 -UiCollection, 通过选择器的find(), untilFind()方法返回的对象。可以对其进行操作或者获取其信息。 - -### UiCollection.size() -返回集合中的控件数。 - -### UiCollection.get(i) -* i \ 索引 - -返回集合中第i+1个控件(UiObject)。 - -### UiCollection.each(func) -* func \ 遍历函数 - -遍历集合。例如: -``` -var c = clickable(); -c.each(function(o){ - log(o.text()); -}); -``` - -### empty() -返回控件集合是否为空。 - -### nonEmpty() -返回控件集合是否非空。 - -### filter(filter) -* filter \ 过滤函数。参数为UiObject,返回值为Boolean。 - -过滤出控件集合中符合条件的子控件。例如要过滤出所有子控件数目为1的控件为: -``` -var newCollection = collection.filter(function(obj){ - return obj.childCount() == 1; -}); -``` - -### find(selector) -* selector \ 选择器 - -根据selector所确定的条件在该控件集合的控件和**子控件**找到所有符合条件的控件并返回控件集合。 - -注意这会递归地遍历控件集合里所有的控件以及他们的子控件。和filter函数不同。 - -例如: -``` -var names = id("name"); -var clickableNames = names.find(clickable()); -``` - -## findOne(selector) -* selector \ 选择器 - -根据selector所确定的条件在该控件集合中找到一个符合条件的控件并返回控件。若找不到则返回null。 - -### UiCollection.click() -点击集合中所有控件,并返回是否全部点击成功。 - -### UiCollection.longClick() -长按集合中所有控件,并返回是否全部操作成功。 - -### UiCollection.copy() -对集合中所有控件执行复制操作,并返回是否全部操作成功。 - -### UiCollection.paste() -对集合中所有控件执行粘贴操作,并返回是否全部操作成功。 - -### UiCollection.select() -对集合中所有控件执行选中操作,并返回是否全部操作成功。 - -### UiCollection.cut() -对集合中所有控件执行剪切操作,并返回是否全部操作成功。 - -### UiCollection.collapse() -对集合中所有控件执行折叠操作,并返回是否全部操作成功。 - -### UiCollection.expand() -对集合中所有控件执行展开操作,并返回是否全部操作成功。 - -### UiCollection.show() -对集合中所有控件执行显示操作,并返回是否全部操作成功。 - -### UiCollection.scrollForward() -对集合中所有控件执行向前滑的操作,并返回是否全部操作成功。 - -### UiCollection.scrollBackward() -对集合中所有控件执行向后滑的操作,并返回是否全部操作成功。 - -### UiCollection.scrollUp() -对集合中所有控件执行向上滑的操作,并返回是否全部操作成功。 - -### UiCollection.scrollDown() -对集合中所有控件执行向下滑的操作,并返回是否全部操作成功。 - -### UiCollection.scrollLeft() -对集合中所有控件执行向左滑的操作,并返回是否全部操作成功。 - -### UiCollection.scrollRight() -对集合中所有控件执行向右滑的操作,并返回是否全部操作成功。 - -### UiCollection.contextClick() - -### UiCollection.setSelection(start, end) -* start \ 文字选中开始位置 -* end \ 文字选中结束位置 - -对集合中所有控件设置文字选中区域,并返回是否全部操作成功。 - -### UiCollection.setText(text) -* text \ 要设置的文本 -对集合中所有控件设置文本,并返回是否全部操作成功。 - -# 控件 - -UiObject, 选择器的findOne方法返回的对象。和UiCollection有相似的方法,不再赘述。除此之外还有以下方法。 - -### child(i) -* i \ 子控件索引 - -返回第i+1个子控件(UiObject)。 - -### parent() -返回父控件(UiObject)。 - -### children() -返回该控件的所有子控件组成的控件集合。 - -### childCount() -返回子控件数目。 - -### bounds() -返回控件在屏幕上的范围,其值是一个\[Rect\]对象。 - -### boundsInParent() -返回控件在父控件中的范围,其值是一个\[Rect\]对象。 - -### drawingOrder() -返回控件的绘制次序。 - -### id() -返回控件的id,可能为null。 - -### text() -返回控件的文本,如果控件没有文本,返回""。 - -### findByText(text) -* text \ 文本 - -根据文本text在子控件中递归地寻找并返回文本或描述(desc)**包含**这段文本text的控件,返回它们组成的集合。。 - -### find(selector) -* selector \ 选择器 - -根据选择器selector在子控件中递归地寻找符合条件的控件,返回它们组成的集合。 - -### findOne - -### find(selector) -* selector \ 选择器 - -根据选择器selector在子控件中递归地寻找一个符合条件的控件。找不到则返回null。 - -# Rect - -UiObject.bounds(), UiObject.boundsInParent()返回的对象。表示一个长方形。 - -### Rect.left -长方形左边界的x坐标、 - -### Rect.right -长方形左边界的x坐标、 - -### Rect.top -长方形上边界的y坐标、 - -### Rect.bottom -长方形下边界的y坐标、 - -### Rect.centerX() -长方形中点x坐标。 - -### Rect.centerY() -长方形中点y坐标。 - -### Rect.width() -长方形宽度。通常可以作为控件宽度。 - -### Rect.height() -长方形高度。通常可以作为控件高度。 - -### Rect.contains(r) -* r \ - -返回是否包含另一个长方形r。 - -### Rect.intersect(r) -* r \ - -返回是否和另一个长方形相交。 diff --git a/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md b/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md deleted file mode 100644 index 4acfd791..00000000 --- a/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md +++ /dev/null @@ -1,176 +0,0 @@ - -注意:本章节的函数在后续版本很可能有改动!请勿过分依赖本章节函数的副作用。推荐使用RootAutomator(见《需要Root权限的触摸与多点触摸》)代替本章的触摸函数。 - -以下函数均需要root权限,可以实现任意位置的点击、滑动、长按、模拟物理按键等。 - -这些函数通常首字母大写以表示其特殊的权限。 -这些函数均不返回任何值。 -并且,这些函数的执行是异步的、非实时的,在不同机型上所用的时间不同。脚本不会等待动作执行完成才继续执行。因此最好在每个函数之后加上适当的sleep来达到期望的效果。 - - -例如: -``` -Tap(100, 100); -sleep(500); -``` - -注意,动作的执行可能无法被停止,例如: -``` -for(var i = 0; i < 100; i++){ - Tap(100, 100); -} -``` -这段代码执行后可能会出现在任务管理中停止脚本后点击仍然继续的情况。 -因此,强烈建议在每个动作后加上延时: -``` -for(var i = 0; i < 100; i++){ - Tap(100, 100); - sleep(500); -} -``` - - -### Tap(x, y) -* x, y \ 要点击的坐标。 - -点击位置(x, y), 您可以通过"开发者选项"开启指针位置来确定点击坐标。 - -### Swipe(x1, y1, x2, y2, \[duration\]) -* x1, y1 \ 滑动起点的坐标 -* x2, y2 \ 滑动终点的坐标 -* duration \ 滑动动作所用的时间 - -滑动。从(x1, y1)位置滑动到(x2, y2)位置。 - -### Home() -按下Home键。 - -### Back() -按下返回键。 - -### Power() -按下电源键。 - -### Menu() -按下菜单键。 - -### Up() -模拟按下物理按键上。 - -### Down() -模拟按下物理按键下。 - -### Left() -模拟按下物理按键左。 - -### Right() -模拟按下物理按键右。 - -### OK() -模拟按下物理按键确定。 - -### VolumeUp() -按下音量上键。 - -### VolumeDown() -按键音量上键。 - -### Text(text) -* text 要输入的文字 -输入文字text。例如`Text("测试");` - -### Camera() -模拟按下照相键。 - -### KeyCode(code) -* code | 要按下的按键的数字代码或名称。参见下表。 -模拟物理按键。例如`KeyCode(29)`和`KeyCode("KEYCODE_A")`是按下A键。 - -KeyCode KeyEvent Value -* KEYCODE_MENU 1 -* KEYCODE_SOFT_RIGHT 2 -* KEYCODE_HOME 3 -* KEYCODE_BACK 4 -* KEYCODE_CALL 5 -* KEYCODE_ENDCALL 6 -* KEYCODE_0 7 -* KEYCODE_1 8 -* KEYCODE_2 9 -* KEYCODE_3 10 -* KEYCODE_4 11 -* KEYCODE_5 12 -* KEYCODE_6 13 -* KEYCODE_7 14 -* KEYCODE_8 15 -* KEYCODE_9 16 -* KEYCODE_STAR 17 -* KEYCODE_POUND 18 -* KEYCODE_DPAD_UP 19 -* KEYCODE_DPAD_DOWN 20 -* KEYCODE_DPAD_LEFT 21 -* KEYCODE_DPAD_RIGHT 22 -* KEYCODE_DPAD_CENTER 23 -* KEYCODE_VOLUME_UP 24 -* KEYCODE_VOLUME_DOWN 25 -* KEYCODE_POWER 26 -* KEYCODE_CAMERA 27 -* KEYCODE_CLEAR 28 -* KEYCODE_A 29 -* KEYCODE_B 30 -* KEYCODE_C 31 -* KEYCODE_D 32 -* KEYCODE_E 33 -* KEYCODE_F 34 -* KEYCODE_G 35 -* KEYCODE_H 36 -* KEYCODE_I 37 -* KEYCODE_J 38 -* KEYCODE_K 39 -* KEYCODE_L 40 -* KEYCODE_M 41 -* KEYCODE_N 42 -* KEYCODE_O 43 -* KEYCODE_P 44 -* KEYCODE_Q 45 -* KEYCODE_R 46 -* KEYCODE_S 47 -* KEYCODE_T 48 -* KEYCODE_U 49 -* KEYCODE_V 50 -* KEYCODE_W 51 -* KEYCODE_X 52 -* KEYCODE_Y 53 -* KEYCODE_Z 54 -* KEYCODE_COMMA 55 -* KEYCODE_PERIOD 56 -* KEYCODE_ALT_LEFT 57 -* KEYCODE_ALT_RIGHT 58 -* KEYCODE_SHIFT_LEFT 59 -* KEYCODE_SHIFT_RIGHT 60 -* KEYCODE_TAB 61 -* KEYCODE_SPACE 62 -* KEYCODE_SYM 63 -* KEYCODE_EXPLORER 64 -* KEYCODE_ENVELOPE 65 -* KEYCODE_ENTER 66 -* KEYCODE_DEL 67 -* KEYCODE_GRAVE 68 -* KEYCODE_MINUS 69 -* KEYCODE_EQUALS 70 -* KEYCODE_LEFT_BRACKET 71 -* KEYCODE_RIGHT_BRACKET 72 -* KEYCODE_BACKSLASH 73 -* KEYCODE_SEMICOLON 74 -* KEYCODE_APOSTROPHE 75 -* KEYCODE_SLASH 76 -* KEYCODE_AT 77 -* KEYCODE_NUM 78 -* KEYCODE_HEADSETHOOK 79 -* KEYCODE_FOCUS 80 -* KEYCODE_PLUS 81 -* KEYCODE_MENU 82 -* KEYCODE_NOTIFICATION 83 -* KEYCODE_SEARCH 84 -* TAG_LAST_ KEYCODE 85 - - diff --git a/app/src/main/assets/help/documentation/需要Root权限的触摸与多点触摸.md b/app/src/main/assets/help/documentation/需要Root权限的触摸与多点触摸.md deleted file mode 100644 index c5877897..00000000 --- a/app/src/main/assets/help/documentation/需要Root权限的触摸与多点触摸.md +++ /dev/null @@ -1,71 +0,0 @@ -# RootAutomator - -RootAutomator是一个使用Root权限来模拟触摸的对象,用它可以完成触摸与多点触摸,并且这些动作的执行没有延迟。 - -``` -var ra = RootAutomator(); -``` - -### RootAutomator.tap(x, y\[, id\]) -* x \ 横坐标 -* y \ 纵坐标 -* id \ 多点触摸id,可选,默认为1,可以通过setDefaultId指定。 - -点击位置(x, y)。其中id是一个整数值,用于区分多点触摸,不同的id表示不同的"手指",例如: -``` -var ra = RootAutomator(); -//让"手指1"点击位置(100, 100) -ra.tap(100, 100, 1); -//让"手指2"点击位置(200, 200); -ra.tap(200, 200, 2); -ra.exit(); -``` -如果不需要多点触摸,则不需要id这个参数。 -多点触摸通常用于手势或游戏操作,例如模拟双指捏合、双指上滑等。 -### RootAutomator.swipe(x1, x2, y1, y2\[, duration, id\]) -* x1 \ 滑动起点横坐标 -* y1 \ 滑动起点纵坐标 -* x2 \ 滑动终点横坐标 -* y2 \ 滑动终点纵坐标 -* duration \ 滑动时长,单位毫秒,默认值为300 -* id \ 多点触摸id,可选,默认为1 - -模拟一次从(x1, y1)到(x2, y2)的时间为duration毫秒的滑动。 - -### RootAutomator.press(x, y, duration[\, id\]) -* x \ 横坐标 -* y \ 纵坐标 -* duration \ 按下时长 -* id \ 多点触摸id,可选,默认为1 - -模拟按下位置(x, y),时长为duration毫秒。 - -### RootAutomator.longPress(x, y[\, id\]) -* x \ 横坐标 -* y \ 纵坐标 -* duration \ 按下时长 -* id \ 多点触摸id,可选,默认为1 - -模拟长按位置(x, y)。 - -以上为简单模拟触摸操作的函数。如果要模拟一些复杂的手势,需要更底层的函数。 - -### RootAutomator.touchDown(x, y[\, id\]) -* x \ 横坐标 -* y \ 纵坐标 -* id \ 多点触摸id,可选,默认为1 - -模拟手指按下位置(x, y)。 - -### RootAutomator.touchMove(x, y[\, id\]) -* x \ 横坐标 -* y \ 纵坐标 -* id \ 多点触摸id,可选,默认为1 - -模拟移动手指到位置(x, y)。 - -### RootAutomator.touchUp(\[id\]) -* id \ 多点触摸id,可选,默认为1 - -模拟手指弹起。 - diff --git a/app/src/main/assets/help/w3c/Function 对象(类).html b/app/src/main/assets/help/w3c/Function 对象(类).html deleted file mode 100644 index dec0e783..00000000 --- a/app/src/main/assets/help/w3c/Function 对象(类).html +++ /dev/null @@ -1,148 +0,0 @@ -
- -

ECMAScript Function 对象(类)

- -
- -
- - -
-

ECMAScript 的函数实际上是功能完整的对象。

-
- - -
-

Function 对象(类)

- -

ECMAScript 最令人感兴趣的可能莫过于函数实际上是功能完整的对象。

- -

Function 类可以表示开发者定义的任何函数。

- -

用 Function 类直接创建函数的语法如下:

- -
var function_name = new function(arg1, arg2, ..., argN, function_body)
- -

在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。

- -

记得下面这个函数吗?

- -
-function sayHi(sName, sMessage) {
-  alert("Hello " + sName + sMessage);
-}
-
- -

还可以这样定义它:

- -
-var sayHi 
-= 
-new Function("sName", "sMessage", "alert(\"Hello \" + sName + sMessage);");
-
- -

虽然由于字符串的关系,这种形式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用 Function 类明确创建的函数行为是相同的。

- -

请看下面这个例子:

- -
-function doAdd(iNum) {
-  alert(iNum + 20);
-}
-
-function doAdd(iNum) {
-  alert(iNum + 10);
-}
-
-doAdd(10);	//输出 "20"
-
- -

如你所知,第二个函数重载了第一个函数,使 doAdd(10) 输出了 "20",而不是 "30"。

- -

如果以下面的形式重写该代码块,这个概念就清楚了:

- -
-var doAdd = new Function("iNum", "alert(iNum + 20)");
-var doAdd = new Function("iNum", "alert(iNum + 10)");
-doAdd(10);
-
- -

请观察这段代码,很显然,doAdd 的值被改成了指向不同对象的指针。函数名只是指向函数对象的引用值,行为就像其他对象一样。甚至可以使两个变量指向同一个函数:

- -
-var doAdd = new Function("iNum", "alert(iNum + 10)");
-var alsodoAdd = doAdd;
-doAdd(10);	//输出 "20"
-alsodoAdd(10);	//输出 "20"
-
- -

在这里,变量 doAdd 被定义为函数,然后 alsodoAdd 被声明为指向同一个函数的指针。用这两个变量都可以执行该函数的代码,并输出相同的结果 - "20"。因此,如果函数名只是指向函数的变量,那么可以把函数作为参数传递给另一个函数吗?回答是肯定的!

- -
-function callAnotherFunc(fnFunction, vArgument) {
-  fnFunction(vArgument);
-}
-
-var doAdd = new Function("iNum", "alert(iNum + 10)");
-
-callAnotherFunc(doAdd, 10);	//输出 "20"
-
- -

在上面的例子中,callAnotherFunc() 有两个参数 - 要调用的函数和传递给该函数的参数。这段代码把 doAdd() 传递给 callAnotherFunc() 函数,参数是 10,输出 "20"。

- -

注意:尽管可以使用 Function 构造函数创建函数,但最好不要使用它,因为用它定义函数比用传统方式要慢得多。不过,所有函数都应看作 Function 类的实例。

-
- - -
-

Function 对象的 length 属性

- -

如前所述,函数属于引用类型,所以它们也有属性和方法。

- -

ECMAScript 定义的属性 length 声明了函数期望的参数个数。例如:

- -
-function doAdd(iNum) {
-  alert(iNum + 10);
-}
-
-function sayHi() {
-  alert("Hi");
-}
-
-alert(doAdd.length);	//输出 "1"
-alert(sayHi.length);	//输出 "0"
-
- -

函数 doAdd() 定义了一个参数,因此它的 length 是 1;sayHi() 没有定义参数,所以 length 是 0。

- -

记住,无论定义了几个参数,ECMAScript 可以接受任意多个参数(最多 25 个),这一点在《函数概述》这一章中讲解过。属性 length 只是为查看默认情况下预期的参数个数提供了一种简便方式。

- -
- - -
-

Function 对象的方法

- -

Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法。这两个方法返回的都是函数的源代码,在调试时尤其有用。例如:

- -
-function doAdd(iNum) {
-  alert(iNum + 10);
-}
-
-document.write(doAdd.toString());
-
- -

上面这段代码输出了 doAdd() 函数的文本。亲自试一试

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/arguments 对象.html b/app/src/main/assets/help/w3c/arguments 对象.html deleted file mode 100644 index 37194a90..00000000 --- a/app/src/main/assets/help/w3c/arguments 对象.html +++ /dev/null @@ -1,85 +0,0 @@ -
- -

ECMAScript arguments 对象

- -
- -
- - -
-

arguments 对象

- -

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。

- -

例如,在函数 sayHi() 中,第一个参数是 message。用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。

- -

因此,无需明确命名参数,就可以重写函数:

- -
-function sayHi() {
-  if (arguments[0] == "bye") {
-    return;
-  }
-
-  alert(arguments[0]);
-}
-
-
- - -
-

检测参数个数

- -

还可以用 arguments 对象检测函数的参数个数,引用属性 arguments.length 即可。

- -

下面的代码将输出每次调用函数使用的参数个数:

- -
-function howManyArgs() {
-  alert(arguments.length);
-}
-
-howManyArgs("string", 45);
-howManyArgs();
-howManyArgs(12);
-
- -

上面这段代码将依次显示 "2"、"0" 和 "1"。

- -

注释:与其他程序设计语言不同,ECMAScript 不会验证传递给函数的参数个数是否等于函数定义的参数个数。开发者定义的函数都可以接受任意个数的参数(根据 Netscape 的文档,最多可接受 255 个),而不会引发任何错误。任何遗漏的参数都会以 undefined 传递给函数,多余的函数将忽略。

-
- - -
-

模拟函数重载

- -

用 arguments 对象判断传递给函数的参数个数,即可模拟函数重载:

- -
-function doAdd() {
-  if(arguments.length == 1) {
-    alert(arguments[0] + 5);
-  } else if(arguments.length == 2) {
-    alert(arguments[0] + arguments[1]);
-  }
-}
-
-doAdd(10);	//输出 "15"
-doAdd(40, 20);	//输出 "60"
-
- -

当只有一个参数时,doAdd() 函数给参数加 5。如果有两个参数,则会把两个参数相加,返回它们的和。所以,doAdd(10) 输出的是 "15",而 doAdd(40, 20) 输出的是 "60"。

- -

虽然不如重载那么好,不过已足以避开 ECMAScript 的这种限制。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/break 和 continue 语句.html b/app/src/main/assets/help/w3c/break 和 continue 语句.html deleted file mode 100644 index ffd80636..00000000 --- a/app/src/main/assets/help/w3c/break 和 continue 语句.html +++ /dev/null @@ -1,114 +0,0 @@ -
- -

ECMAScript break 和 continue 语句

- -
- -
- - -
-

break 和 continue 语句对循环中的代码执行提供了更严格的控制。

-
- - -
-

break 和 continue 语句的不同之处

- -

break 语句可以立即退出循环,阻止再次反复执行任何代码。

- -

而 continue 语句只是退出当前循环,根据控制表达式还允许继续进行下一次循环。

- -

例如:

- -
-var iNum = 0;
-
-for (var i=1; i<10; i++) {
-  if (i % 5 == 0) {
-    break;
-  }
-  iNum++;
-}
-alert(iNum);	//输出 "4"
-
- -

在以上代码中,for 循环从 1 到 10 迭代变量 i。在循环主体中,if 语句将(使用取模运算符)检查 i 的值是否能被 5 整除。如果能被 5 整除,将执行 break 语句。alert 显示 "4",即退出循环前执行循环的次数。

- -

如果用 continue 语句代替这个例子中的 break 语句,结果将不同:

- -
-var iNum = 0;
-
-for (var i=1; i<10; i++) {
-  if (i % 5 == 0) {
-    continue;
-  }
-  iNum++;
-}
-alert(iNum);	//输出 "8"
-
- -

这里,alert 将显示 "8",即执行循环的次数。可能执行的循环总数为 9,不过当 i 的值为 5 时,将执行 continue 语句,会使循环跳过表达式 iNum++,返回循环开头。

-
- - -
-

与有标签的语句一起使用

- -

break 语句和 continue 语句都可以与有标签的语句联合使用,返回代码中的特定位置。

- -

通常,当循环内部还有循环时,会这样做,例如:

- -
-var iNum = 0;
-
-outermost:
-for (var i=0; i<10; i++) {
-  for (var j=0; j<10; j++) {
-    if (i == 5 && j == 5) {
-    break outermost;
-  }
-  iNum++;
-  }
-}
-
-alert(iNum);	//输出 "55"
-
- -

在上面的例子中,标签 outermost 表示的是第一个 for 语句。正常情况下,每个 for 语句执行 10 次代码块,这意味着 iNum++ 正常情况下将被执行 100 次,在执行完成时,iNum 应该等于 100。这里的 break 语句有一个参数,即停止循环后要跳转到的语句的标签。这样 break 语句不止能跳出内部 for 语句(即使用变量 j 的语句),还能跳出外部 for 语句(即使用变量 i 的语句)。因此,iNum 最后的值是 55,因为当 i 和 j 的值都等于 5 时,循环将终止。

- -

可以以相同的方式使用 continue 语句:

- -
-var iNum = 0;
-
-outermost:
-for (var i=0; i<10; i++) {
-  for (var j=0; j<10; j++) {
-    if (i == 5 && j == 5) {
-    continue outermost;
-  }
-  iNum++;
-  }
-}
-
-alert(iNum);	//输出 "95"
-
- -

在上例中,continue 语句会迫使循环继续,不止是内部循环,外部循环也如此。当 j 等于 5 时出现这种情况,意味着内部循环将减少 5 次迭代,致使 iNum 的值为 95。

- -

提示:可以看出,与 break 和 continue 联合使用的有标签语句非常强大,不过过度使用它们会给调试代码带来麻烦。要确保使用的标签具有说明性,同时不要嵌套太多层循环。

- -

提示:想了解什么是有标签语句,请阅读 ECMAScript 标签语句 这一节。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/if 语句.html b/app/src/main/assets/help/w3c/if 语句.html deleted file mode 100644 index e13bc32b..00000000 --- a/app/src/main/assets/help/w3c/if 语句.html +++ /dev/null @@ -1,77 +0,0 @@ -
- -

ECMAScript if 语句

- -
- -
- -
-

if 语句是 ECMAScript 中最常用的语句之一。

-
- -
-

ECMAScript 语句

- -

ECMA - 262 描述了 ECMAScript 的几种语句(statement)。

- -

语句主要定义了 ECMAScript 的大部分语句,通常采用一个或多个关键字,完成给定的任务。

- -

语句可以非常简单,例如通知函数退出,也可以非常复杂,如声明一组要反复执行的命令。

- -

在《ECMAScript 语句》这一章,我们介绍了所有标准的 ECMAScript 语句。

-
- - -
-

if 语句

- -

if 语句是 ECMAScript 中最常用的语句之一,事实上在许多计算机语言中都是如此。

- -

if 语句的语法:

- -
if (condition) statement1 else statement2
- -

其中 condition 可以是任何表达式,计算的结果甚至不必是真正的 boolean 值,ECMAScript 会把它转换成 boolean 值。

- -

如果条件计算结果为 true,则执行 statement1;如果条件计算结果为 false,则执行 statement2

- -

每个语句都可以是单行代码,也可以是代码块。

- -

例如:

- -
-if (i > 30)
-  {alert("大于 30");}
-else
-  {alert("小于等于 30");}
-
- -

提示:使用代码块被认为是一种最佳的编程实践,即使要执行的代码只有一行。这样做可以使每个条件要执行什么一目了然。

- -

还可以串联多个 if 语句。就像这样:

- -
if (condition1) statement1 else if (condition2) statement2 else statement3
- -

例如:

- -
-if (i > 30) {
-  alert("大于 30");
-} else if (i < 0) {
-  alert("小于 0");
-} else {
-  alert("在 0 到 30 之间");
-}
-
-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/switch 语句.html b/app/src/main/assets/help/w3c/switch 语句.html deleted file mode 100644 index 21257e89..00000000 --- a/app/src/main/assets/help/w3c/switch 语句.html +++ /dev/null @@ -1,98 +0,0 @@ -
- -

ECMAScript switch 语句

- -
- -
- - -
-

switch 语句

- -

switch 语句是 if 语句的兄弟语句。

- -

开发者可以用 switch 语句为表达式提供一系列的情况(case)。

- -

switch 语句的语法:

- -
switch (expression)
-  case value: statement;
-    break;
-  case value: statement;
-    break;
-  case value: statement;
-    break;
-  case value: statement;
-    break;
-...
-  case value: statement;
-    break;
-  default: statement;
-
- -

每个情况(case)都是表示“如果 expression 等于 value,就执行 statement”。

- -

关键字 break 会使代码跳出 switch 语句。如果没有关键字 break,代码执行就会继续进入下一个 case。

- -

关键字 default 说明了表达式的结果不等于任何一种情况时的操作(事实上,它相对于 else 从句)。

- -

switch 语句主要是为避免让开发者编写下面的代码:

- -
-if (i == 20)
-  alert("20");
-else if (i == 30)
-  alert("30");
-else if (i == 40)
-  alert("40");
-else
-  alert("other");
-
- -

等价的 switch 语句是这样的:

- -
-switch (i) {
-  case 20: alert("20");
-    break;
-  case 30: alert("30");
-    break;
-  case 40: alert("40");
-    break;
-  default: alert("other");
-}
-
-
- -
-

ECMAScript 和 Java 中的 switch 语句

- -

ECMAScript 和 Java 中的 switch 语句有两点不同。在 ECMAScript 中,switch 语句可以用于字符串,而且能用不是常量的值说明情况:

- -
-var BLUE = "blue", RED = "red", GREEN  = "green";
-
-switch (sColor) {
-  case BLUE: alert("Blue");
-    break;
-  case RED: alert("Red");
-    break;
-  case GREEN: alert("Green");
-    break;
-  default: alert("Other");
-}
-
- -

这里,switch 语句用于字符串 sColor,声明 case 使用的是变量 BLUE、RED 和 GREEN,这在 ECMAScript 中是完全有效的。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/with 语句.html b/app/src/main/assets/help/w3c/with 语句.html deleted file mode 100644 index 82b6206c..00000000 --- a/app/src/main/assets/help/w3c/with 语句.html +++ /dev/null @@ -1,41 +0,0 @@ -
- -

ECMAScript with 语句

- -
- -
- - -
-

有标签的语句

- -

with 语句用于设置代码在特定对象中的作用域。

- -

它的语法:

- -
with (expression) statement
- -

例如:

- -
-var sMessage = "hello";
-with(sMessage) {
-  alert(toUpperCase());	//输出 "HELLO"
-}
-
- -

在这个例子中,with 语句用于字符串,所以在调用 toUpperCase() 方法时,解释程序将检查该方法是否是本地函数。如果不是,它将检查伪对象 sMessage,看它是否为该对象的方法。然后,alert 输出 "HELLO",因为解释程序找到了字符串 "hello" 的 toUpperCase() 方法。

- -

提示:with 语句是运行缓慢的代码块,尤其是在已设置了属性值时。大多数情况下,如果可能,最好避免使用它。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/一元运算符.html b/app/src/main/assets/help/w3c/一元运算符.html deleted file mode 100644 index 581665ac..00000000 --- a/app/src/main/assets/help/w3c/一元运算符.html +++ /dev/null @@ -1,215 +0,0 @@ -
- -

ECMAScript 一元运算符

- -
- -
- -
-

一元运算符只有一个参数,即要操作的对象或值。它们是 ECMAScript 中最简单的运算符。

-
- -
-

delete

- -

delete 运算符删除对以前定义的对象属性或方法的引用。例如:

- -
-var o = new Object;
-o.name = "David";
-alert(o.name);	//输出 "David"
-delete o.name;
-alert(o.name);	//输出 "undefined"
-
- - -

在这个例子中,删除了 name 属性,意味着强制解除对它的引用,将其设置为 undefined(即创建的未初始化的变量的值)。

- -

delete 运算符不能删除开发者未定义的属性和方法。例如,下面的代码将引发错误:

- -
delete o.toString;
- -

即使 toString 是有效的方法名,这行代码也会引发错误,因为 toString() 方法是原始的 ECMAScript 方法,不是开发者定义的。

- -
- - -
-

void

- -

void 运算符对任何值返回 undefined。该运算符通常用于避免输出不应该输出的值,例如,从 HTML 的 <a> 元素调用 JavaScript 函数时。要正确做到这一点,函数不能返回有效值,否则浏览器将清空页面,只显示函数的结果。例如:

- -
<a href="javascript:window.open('about:blank')">Click me</a>
- -

如果把这行代码放入 HTML 页面,点击其中的链接,即可看到屏幕上显示 "[object]"。TIY

- -

这是因为 window.open() 方法返回了新打开的窗口的引用。然后该对象将被转换成要显示的字符串。

- -

要避免这种效果,可以用 void 运算符调用 window.open() 函数:

- -
<a href="javascript:void(window.open('about:blank'))">Click me</a>
- -

这使 window.open() 调用返回 undefined,它不是有效值,不会显示在浏览器窗口中。

- -

提示:请记住,没有返回值的函数真正返回的都是 undefined。

-
- - -
-

前增量/前减量运算符

- -

直接从 C(和 Java)借用的两个运算符是前增量运算符和前减量运算符。

- -

所谓前增量运算符,就是数值上加 1,形式是在变量前放两个加号(++):

- -
-var iNum = 10;
-++iNum;
-
- -

第二行代码把 iNum 增加到了 11,它实质上等价于:

- -
-var iNum = 10;
-iNum = iNum + 1;
-
- -

同样,前减量运算符是从数值上减 1,形式是在变量前放两个减号(--):

- -
-var iNum = 10;
---iNum;
-
- -

在这个例子中,第二行代码把 iNum 的值减到 9。

- -

在使用前缀式运算符时,注意增量和减量运算符都发生在计算表达式之前。考虑下面的例子:

- -
-var iNum = 10;
---iNum;
-alert(iNum);	//输出 "9"
-alert(--iNum);	//输出 "8"
-alert(iNum);	//输出 "8"
-
- -

第二行代码对 iNum 进行减量运算,第三行代码显示的结果是("9")。第四行代码又对 iNum 进行减量运算,不过这次前减量运算和输出操作出现在同一个语句中,显示的结果是 "8"。为了证明已实现了所有的减量操作,第五行代码又输出一次"8"。

- -

在算术表达式中,前增量和前减量运算符的优先级是相同的,因此要按照从左到右的顺序计算之。例如:

- -
-var iNum1 = 2;
-var iNum2 = 20;
-var iNum3 = --iNum1 + ++iNum2;	//等于 "22"
-var iNum4 = iNum1 + iNum2;		//等于 "22"
-
- -

在前面的代码中,iNum3 等于 22,因为表达式要计算的是 1 + 21。变量 iNum4 也等于 22,也是 1 + 21。

- -
- - -
-

后增量/后减量运算符

- -

还有两个直接从 C(和 Java)借用的运算符,即后增量运算符和后减量运算符。

- -

后增量运算符也是给数值上加 1,形式是在变量后放两个加号(++):

- -
-var iNum = 10;
-iNum++;
-
- -

不出所料,后减量运算符也是从数值上减 1,形式为在变量后加两个减号(--):

- -
-var iNum = 10;
-iNum--;
-
- -

第二行代码把 iNum 的 值减到 9。

- -

与前缀式运算符不同的是,后缀式运算符是在计算过包含它们的表达式后才进行增量或减量运算的。考虑以下的例子:

- -
-var iNum = 10;
-iNum--;
-alert(iNum);	//输出 "9"
-alert(iNum--);	//输出 "9"
-alert(iNum);	//输出 "8"
-
- -

与前缀式运算符的例子相似,第二行代码对 iNum 进行减量运算,第三行代码显示结果("9")。第四行代码继续显示 iNum 的值,不过这次是在同一语句中应用减量运算符。由于减量运算发生在计算过表达式之后,所以这条语句显示的数是 "9"。执行了第五行代码后,alert 函数显示的是 "8",因为在执行第四行代码之后和执行第五行代码之前,执行了后减量运算。

- -

在算术表达式中,后增量和后减量运算符的优先级是相同的,因此要按照从左到右的顺序计算之。例如:

- -
-var iNum1 = 2;
-var iNum2 = 20;
-var iNum3 = iNum1-- + iNum2++;	//等于 "22"
-var iNum4 = iNum1 + iNum2;		//等于 "22"
-
- -

在前面的代码中,iNum3 等于 22,因为表达式要计算的是 2 + 20。变量 iNum4 也等于 22,不过它计算的是 1 + 21,因为增量和减量运算都在给 iNum3 赋值后才发生。

- -
- - -
-

一元加法和一元减法

- -

大多数人都熟悉一元加法和一元减法,它们在 ECMAScript 中的用法与您高中数学中学到的用法相同。

- -

一元加法本质上对数字无任何影响:

- -
-var iNum = 20;
-iNum = +iNum;
-alert(iNum);	//输出 "20"
-
- -

这段代码对数字 20 应用了一元加法,返回的还是 20。

- -

尽管一元加法对数字无作用,但对字符串却有有趣的效果,会把字符串转换成数字。

- -
-var sNum = "20";
-alert(typeof sNum);	//输出 "string"
-var iNum = +sNum;
-alert(typeof iNum);	//输出 "number"
-
- -

这段代码把字符串 "20" 转换成真正的数字。当一元加法运算符对字符串进行操作时,它计算字符串的方式与 parseInt() 相似,主要的不同是只有对以 "0x" 开头的字符串(表示十六进制数字),一元运算符才能把它转换成十进制的值。因此,用一元加法转换 "010",得到的总是 10,而 "0xB" 将被转换成 11。

- -

另一方面,一元减法就是对数值求负(例如把 20 转换成 -20):

- -
-var iNum = 20;
-iNum = -iNum;
-alert(iNum);	//输出 "-20"
-
- -

与一元加法运算符相似,一元减法运算符也会把字符串转换成近似的数字,此外还会对该值求负。例如:

- -
-var sNum = "20";
-alert(typeof sNum);	//输出 "string"
-var iNum = -sNum;
-alert(iNum);		//输出 "-20"
-alert(typeof iNum);	//输出 "number"
-
- -

在上面的代码中,一元减法运算符将把字符串 "-20" 转换成 -20(一元减法运算符对十六进制和十进制的处理方式与一元加法运算符相似,只是它还会对该值求负)。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/乘性运算符.html b/app/src/main/assets/help/w3c/乘性运算符.html deleted file mode 100644 index 8e8cb641..00000000 --- a/app/src/main/assets/help/w3c/乘性运算符.html +++ /dev/null @@ -1,88 +0,0 @@ -
- -

ECMAScript 乘性运算符

- -
- -
- -
-

ECMAScript 的乘性运算符与 Java、C、Perl 等于语言中的同类运算符的运算方式相似。

-

需要注意的是,乘性运算符还具有一些自动转换功能。

-
- -
-

乘法运算符

- -

乘法运算符由星号(*)表示,用于两数相乘。

- -

ECMAScript 中的乘法语法与 C 语言中的相同:

- -
var iResult = 12 * 34
- -

不过,在处理特殊值时,ECMAScript 中的乘法还有一些特殊行为:

- -
    -
  • 如果结果太大或太小,那么生成的结果是 Infinity 或 -Infinity。
  • -
  • 如果某个运算数是 NaN,结果为 NaN。
  • -
  • Infinity 乘以 0,结果为 NaN。
  • -
  • Infinity 乘以 0 以外的任何数字,结果为 Infinity 或 -Infinity。
  • -
  • Infinity 乘以 Infinity,结果为 Infinity。
  • -
- -

注释:如果运算数是数字,那么执行常规的乘法运算,即两个正数或两个负数为正数,两个运算数符号不同,结果为负数。

-
- - -
-

除法运算符

- -

除法运算符由斜杠(/)表示,用第二个运算数除第一个运算数:

- -
-var iResult = 88 /11;
-
- -

与乘法运算符相似,在处理特殊值时,除法运算符也有一些特殊行为:

- -
    -
  • 如果结果太大或太小,那么生成的结果是 Infinity 或 -Infinity。
  • -
  • 如果某个运算数是 NaN,结果为 NaN。
  • -
  • Infinity 被 Infinity 除,结果为 NaN。
  • -
  • Infinity 被任何数字除,结果为 Infinity。
  • -
  • 0 除一个任何非无穷大的数字,结果为 NaN。
  • -
  • Infinity 被 0 以外的任何数字除,结果为 Infinity 或 -Infinity。
  • -
- -

注释:如果运算数是数字,那么执行常规的除法运算,即两个正数或两个负数为正数,两个运算数符号不同,结果为负数。

-
- - -
-

取模运算符

- -

除法(余数)运算符由百分号(%)表示,使用方法如下:

- -
var iResult = 26%5; //等于 1
- -

与其他乘性运算符相似,对于特殊值,取模运算符也有特殊的行为:

- -
    -
  • 如果被除数是 Infinity,或除数是 0,结果为 NaN。
  • -
  • Infinity 被 Infinity 除,结果为 NaN。
  • -
  • 如果除数是无穷大的数,结果为被除数。
  • -
  • 如果被除数为 0,结果为 0。
  • -
- -

注释:如果运算数是数字,那么执行常规的算术除法运算,返回除法运算得到的余数。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/位运算符.html b/app/src/main/assets/help/w3c/位运算符.html deleted file mode 100644 index e5fc7094..00000000 --- a/app/src/main/assets/help/w3c/位运算符.html +++ /dev/null @@ -1,357 +0,0 @@ -
- -

ECMAScript 位运算符

- -
- -
- - -
-

位运算符是在数字底层(即表示数字的 32 个数位)进行操作的。

-
- - -
-

重温整数

- -

ECMAScript 整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。在 ECMAScript 中,所有整数字面量默认都是有符号整数,这意味着什么呢?

- -

有符号整数使用 31 位表示整数的数值,用第 32 位表示整数的符号,0 表示正数,1 表示负数。数值范围从 -2147483648 到 2147483647。

- -

可以以两种不同的方式存储二进制形式的有符号整数,一种用于存储正数,一种用于存储负数。正数是以真二进制形式存储的,前 31 位中的每一位都表示 2 的幂,从第 1 位(位 0)开始,表示 20,第 2 位(位 1)表示 21。没用到的位用 0 填充,即忽略不计。例如,下图展示的是数 18 的表示法。

- -32 位二进制表示的有符号整数 - - -

18 的二进制版本只用了前 5 位,它们是这个数字的有效位。把数字转换成二进制字符串,就能看到有效位:

- -
-var iNum = 18;
-alert(iNum.toString(2));	//输出 "10010"
-
- -

这段代码只输出 "10010",而不是 18 的 32 位表示。其他的数位并不重要,因为仅使用前 5 位即可确定这个十进制数值。如下图所示:

- -5 位二进制表示的整数 18 - -

负数也存储为二进制代码,不过采用的形式是二进制补码。计算数字二进制补码的步骤有三步:

- -
    -
  1. 确定该数字的非负版本的二进制表示(例如,要计算 -18的二进制补码,首先要确定 18 的二进制表示)
  2. -
  3. 求得二进制反码,即要把 0 替换为 1,把 1 替换为 0
  4. -
  5. 在二进制反码上加 1
  6. -
- -

要确定 -18 的二进制表示,首先必须得到 18 的二进制表示,如下所示:

- -
0000 0000 0000 0000 0000 0000 0001 0010
- -

接下来,计算二进制反码,如下所示:

- -
1111 1111 1111 1111 1111 1111 1110 1101
- -

最后,在二进制反码上加 1,如下所示:

- -
-1111 1111 1111 1111 1111 1111 1110 1101
-                                      1
----------------------------------------
-1111 1111 1111 1111 1111 1111 1110 1110
-
- -

因此,-18 的二进制表示即 1111 1111 1111 1111 1111 1111 1110 1110。记住,在处理有符号整数时,开发者不能访问 31 位。

- -

有趣的是,把负整数转换成二进制字符串后,ECMAScript 并不以二进制补码的形式显示,而是用数字绝对值的标准二进制代码前面加负号的形式输出。例如:

- -
-var iNum = -18;
-alert(iNum.toString(2));	//输出 "-10010"
-
- -

这段代码输出的是 "-10010",而非二进制补码,这是为避免访问位 31。为了简便,ECMAScript 用一种简单的方式处理整数,使得开发者不必关心它们的用法。

- -

另一方面,无符号整数把最后一位作为另一个数位处理。在这种模式中,第 32 位不表示数字的符号,而是值 231。由于这个额外的位,无符号整数的数值范围为 0 到 4294967295。对于小于 2147483647 的整数来说,无符号整数看来与有符号整数一样,而大于 2147483647 的整数则要使用位 31(在有符号整数中,这一位总是 0)。

- -

把无符号整数转换成字符串后,只返回它们的有效位。

- -

注意:所有整数字面量都默认存储为有符号整数。只有 ECMAScript 的位运算符才能创建无符号整数。

-
- - -
-

位运算 NOT

- -

位运算 NOT 由否定号(~)表示,它是 ECMAScript 中为数不多的与二进制算术有关的运算符之一。

- -

位运算 NOT 是三步的处理过程:

- -
    -
  1. 把运算数转换成 32 位数字
  2. -
  3. 把二进制数转换成它的二进制反码
  4. -
  5. 把二进制数转换成浮点数
  6. -
- -

例如:

- -
-var iNum1 = 25;		//25 等于 00000000000000000000000000011001
-var iNum2 = ~iNum1;	//转换为 11111111111111111111111111100110
-alert(iNum2);		//输出 "-26"
-
- -

位运算 NOT 实质上是对数字求负,然后减 1,因此 25 变 -26。用下面的方法也可以得到同样的方法:

- -
-var iNum1 = 25;
-var iNum2 = -iNum1 -1;
-alert(iNum2);	//输出 -26
-
-
- - -
-

位运算 AND

- -

位运算 AND 由和号(&)表示,直接对数字的二进制形式进行运算。它把每个数字中的数位对齐,然后用下面的规则对同一位置上的两个数位进行 AND 运算:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
第一个数字中的数位第二个数字中的数位结果
111
100
010
000
- -

例如,要对数字 25 和 3 进行 AND 运算,代码如下所示:

- -
-var iResult = 25 & 3;
-alert(iResult);	//输出 "1"
-
- -

25 和 3 进行 AND 运算的结果是 1。为什么?分析如下:

- -
- 25 = 0000 0000 0000 0000 0000 0000 0001 1001
-  3 = 0000 0000 0000 0000 0000 0000 0000 0011
----------------------------------------------
-AND = 0000 0000 0000 0000 0000 0000 0000 0001
-
- -

可以看出,在 25 和 3 中,只有一个数位(位 0)存放的都是 1,因此,其他数位生成的都是 0,所以结果为 1。

-
- - -
-

位运算 OR

- -

位运算 OR 由符号(|)表示,也是直接对数字的二进制形式进行运算。在计算每位时,OR 运算符采用下列规则:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
第一个数字中的数位第二个数字中的数位结果
111
101
011
000
- -

仍然使用 AND 运算符所用的例子,对 25 和 3 进行 OR 运算,代码如下:

- -
-var iResult = 25 | 3;
-alert(iResult);	//输出 "27"
-
- -

25 和 3 进行 OR 运算的结果是 27:

- -
-25 = 0000 0000 0000 0000 0000 0000 0001 1001
- 3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
-OR = 0000 0000 0000 0000 0000 0000 0001 1011
-
- -

可以看出,在两个数字中,共有 4 个数位存放的是 1,这些数位被传递给结果。二进制代码 11011 等于 27。

-
- - -
-

位运算 XOR

- -

位运算 XOR 由符号(^)表示,当然,也是直接对二进制形式进行运算。XOR 不同于 OR,当只有一个数位存放的是 1 时,它才返回 1。真值表如下:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
第一个数字中的数位第二个数字中的数位结果
110
101
011
000
- -

对 25 和 3 进行 XOR 运算,代码如下:

- -
-var iResult = 25 ^ 3;
-alert(iResult);	//输出 "26"
-
- -

25 和 3 进行 XOR 运算的结果是 26:

- -
- 25 = 0000 0000 0000 0000 0000 0000 0001 1001
-  3 = 0000 0000 0000 0000 0000 0000 0000 0011
----------------------------------------------
-XOR = 0000 0000 0000 0000 0000 0000 0001 1010
-
- -

可以看出,在两个数字中,共有 4 个数位存放的是 1,这些数位被传递给结果。二进制代码 11010 等于 26。

-
- - -
-

左移运算

- -

左移运算由两个小于号表示(<<)。它把数字中的所有数位向左移动指定的数量。例如,把数字 2(等于二进制中的 10)左移 5 位,结果为 64(等于二进制中的 1000000):

- -
-var iOld = 2;		//等于二进制 10
-var iNew = iOld << 5;	//等于二进制 1000000 十进制 64
-
- -

注意:在左移数位时,数字右边多出 5 个空位。左移运算用 0 填充这些空位,使结果成为完整的 32 位数字。

- -数字 2 进行左移运算 - -

注意:左移运算保留数字的符号位。例如,如果把 -2 左移 5 位,得到的是 -64,而不是 64。“符号仍然存储在第 32 位中吗?”是的,不过这在 ECMAScript 后台进行,开发者不能直接访问第 32 个数位。即使输出二进制字符串形式的负数,显示的也是负号形式(例如,-2 将显示 -10。)

-
- - -
-

有符号右移运算

- -

有符号右移运算符由两个大于号表示(>>)。它把 32 位数字中的所有数位整体右移,同时保留该数的符号(正号或负号)。有符号右移运算符恰好与左移运算相反。例如,把 64 右移 5 位,将变为 2:

- -
-var iOld = 64;		//等于二进制 1000000
-var iNew = iOld >> 5;	//等于二进制 10 十进制 2
-
- -

同样,移动数位后会造成空位。这次,空位位于数字的左侧,但位于符号位之后。ECMAScript 用符号位的值填充这些空位,创建完整的数字,如下图所示:

- -数字 64 进行有符号右移运算 -
- - -
-

无符号右移运算

- -

无符号右移运算符由三个大于号(>>>)表示,它将无符号 32 位数的所有数位整体右移。对于正数,无符号右移运算的结果与有符号右移运算一样。

- -

用有符号右移运算中的例子,把 64 右移 5 位,将变为 2:

- -
-var iOld = 64;		//等于二进制 1000000
-var iNew = iOld >>> 5;	//等于二进制 10 十进制 2
-
- -

对于负数,情况就不同了。

- -

无符号右移运算用 0 填充所有空位。对于正数,这与有符号右移运算的操作一样,而负数则被作为正数来处理。

- -

由于无符号右移运算的结果是一个 32 位的正数,所以负数的无符号右移运算得到的总是一个非常大的数字。例如,如果把 -64 右移 5 位,将得到 134217726。如何得到这种结果的呢?

- -

要实现这一点,需要把这个数字转换成无符号的等价形式(尽管该数字本身还是有符号的),可以通过以下代码获得这种形式:

- -
var iUnsigned64 = -64 >>> 0;
- -

然后,用 Number 类型的 toString() 获取它的真正的位表示,采用的基为 2:

- -
alert(iUnsigned64.toString(2));
- -

这将生成 11111111111111111111111111000000,即有符号整数 -64 的二进制补码表示,不过它等于无符号整数 4294967232。

- -

出于这种原因,使用无符号右移运算符要小心。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/保留字.html b/app/src/main/assets/help/w3c/保留字.html deleted file mode 100644 index bd7297f8..00000000 --- a/app/src/main/assets/help/w3c/保留字.html +++ /dev/null @@ -1,70 +0,0 @@ -
- -

ECMAScript 保留字

- -
- -
- - -
-

本节提供完整的 ECMAScript 保留字列表。

-
- - -
-

ECMAScript 保留字

- -

ECMA-262 定义了 ECMAScript 支持的一套保留字(reserved word)

- -

保留字在某种意思上是为将来的关键字而保留的单词。因此保留字不能被用作变量名或函数名。

- -

ECMA-262 第三版中保留字的完整列表如下:

- -
-abstract
-boolean
-byte
-char
-class
-const
-debugger
-double
-enum
-export
-extends
-final
-float
-goto
-implements
-import
-int
-interface
-long
-native
-package
-private
-protected
-public
-short
-static
-super
-synchronized
-throws
-transient
-volatile
-
- -

注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,该单词将被看做关键字,如此将出现关键字错误。

- -
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/修改对象.html b/app/src/main/assets/help/w3c/修改对象.html deleted file mode 100644 index 85b92d89..00000000 --- a/app/src/main/assets/help/w3c/修改对象.html +++ /dev/null @@ -1,179 +0,0 @@ -
- -

ECMAScript 修改对象

- -
- -
- - -
-

通过使用 ECMAScript,不仅可以创建对象,还可以修改已有对象的行为。

-

prototype 属性不仅可以定义构造函数的属性和方法,还可以为本地对象添加属性和方法。

-
- - -
-

创建新方法

- -

通过已有的方法创建新方法

- -

可以用 prototype 属性为任何已有的类定义新方法,就像处理自己的类一样。例如,还记得 Number 类的 toString() 方法吗?如果给它传递参数 16,它将输出十六进制的字符串。如果这个方法的参数是 2,那么它将输出二进制的字符串。我们可以创建一个方法,可以把数字对象直接转换为十六进制字符串。创建这个方法非常简单:

- -
-Number.prototype.toHexString = function() {
-  return this.toString(16);
-};
-
- -

在此环境中,关键字 this 指向 Number 的实例,因此可完全访问 Number 的所有方法。有了这段代码,可实现下面的操作:

- -
-var iNum = 15;
-alert(iNum.toHexString());		//输出 "F"
-
- -

TIY

- -

由于数字 15 等于十六进制中的 F,因此警告将显示 "F"。

- - -

重命名已有方法

- -

我们还可以为已有的方法命名更易懂的名称。例如,可以给 Array 类添加两个方法 enqueue() 和 dequeue(),只让它们反复调用已有的 push() 和 shift() 方法即可:

- -
-Array.prototype.enqueue = function(vItem) {
-  this.push(vItem);
-};
-
-Array.prototype.dequeue = function() {
-  return this.shift();
-};
-
- -

TIY

- - -

添加与已有方法无关的方法

- -

当然,还可以添加与已有方法无关的方法。例如,假设要判断某个项在数组中的位置,没有本地方法可以做这种事情。我们可以轻松地创建下面的方法:

- -
-Array.prototype.indexOf = function (vItem) {
-  for (var i=0; i<this.length; i++) {
-    if (vItem == this[i]) {
-	  return i;
-	}
-  }
-
-  return -1;
-}
-
- -

该方法 indexOf() 与 String 类的同名方法保持一致,在数组中检索每个项,直到发现与传进来的项相同的项目为止。如果找到相同的项,则返回该项的位置,否则,返回 -1。有了这种定义,我们可以编写下面的代码:

- -
-var aColors = new Array("red","green","blue");
-alert(aColors.indexOf("green"));	//输出 "1"
-
- -

TIY

- - -

为本地对象添加新方法

- -

最后,如果想给 ECMAScript 中每个本地对象添加新方法,必须在 Object 对象的 prototype 属性上定义它。前面的章节我们讲过,所有本地对象都继承了 Object 对象,所以对 Object 对象做任何改变,都会反应在所有本地对象上。例如,如果想添加一个用警告输出对象的当前值的方法,可以采用下面的代码:

- -
-Object.prototype.showValue = function () {
-  alert(this.valueOf());
-};
-
-var str = "hello";
-var iNum = 25;
-str.showValue();		//输出 "hello"
-iNum.showValue();		//输出 "25"
-
- -

TIY

- -

这里,String 和 Number 对象都从 Object 对象继承了 showValue() 方法,分别在它们的对象上调用该方法,将显示 "hello" 和 "25"。

-
- - -
-

重定义已有方法

- -

就像能给已有的类定义新方法一样,也可重定义已有的方法。如前面的章节所述,函数名只是指向函数的指针,因此可以轻松地指向其他函数。如果修改了本地方法,如 toString(),会出现什么情况呢?

- -
-Function.prototype.toString = function() {
-  return "Function code hidden";
-}
-
- -

前面的代码完全合法,运行结果完全符合预期:

- -
-function sayHi() {
-  alert("hi");
-}
-
-alert(sayHi.toString());	//输出 "Function code hidden"
-
- -

TIY

- -

也许你还记得,Function 对象这一章中介绍过 Function 的 toString() 方法通常输出的是函数的源代码。覆盖该方法,可以返回另一个字符串(在这个例子中,可以返回 "Function code hidden")。不过,toString() 指向的原始函数怎么了呢?它将被无用存储单元回收程序回收,因为它被完全废弃了。没有能够恢复原始函数的方法,所以在覆盖原始方法前,比较安全的做法是存储它的指针,以便以后的使用。有时你甚至可能在新方法中调用原始方法:

- -
-Function.prototype.originalToString = Function.prototype.toString;
-
-Function.prototype.toString = function() {
-  if (this.originalToString().length > 100) {
-    return "Function too long to display.";
-  } else {
-    return this.originalToString();
-  }
-};
-
- -

TIY

- -

在这段代码中,第一行代码把对当前 toString() 方法的引用保存在属性 originalToString 中。然后用定制的方法覆盖了 toString() 方法。新方法将检查该函数源代码的长度是否大于 100。如果是,就返回错误信息,说明该函数代码太长,否则调用 originalToString() 方法,返回函数的源代码。

- -
- - -
-

极晚绑定(Very Late Binding)

- -

从技术上讲,根本不存在极晚绑定。本书采用该术语描述 ECMAScript 中的一种现象,即能够在对象实例化后再定义它的方法。例如:

- -
-var o = new Object();
-
-Object.prototype.sayHi = function () {
-  alert("hi");
-};
-
-o.sayHi();
-
- -

TIY

- -

在大多数程序设计语言中,必须在实例化对象之前定义对象的方法。这里,方法 sayHi() 是在创建 Object 类的一个实例之后来添加进来的。在传统语言中不仅没听说过这种操作,也没听说过该方法还会自动赋予 Object 对象的实例并能立即使用(接下来的一行)。

- -

注意:不建议使用极晚绑定方法,因为很难对其跟踪和记录。不过,还是应该了解这种可能。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/值.html b/app/src/main/assets/help/w3c/值.html deleted file mode 100644 index 25b3512e..00000000 --- a/app/src/main/assets/help/w3c/值.html +++ /dev/null @@ -1,56 +0,0 @@ -
- -

ECMAScript 原始值和引用值

- -
- -
- - -
-

在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。

-
- - -
-

原始值和引用值

- -

在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。

- -
-
原始值
-
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
-
引用值
-
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
-
- -

为变量赋值时,ECMAScript 的解释程序必须判断该值是原始类型,还是引用类型。要实现这一点,解释程序则需尝试判断该值是否为 ECMAScript 的原始类型之一,即 Undefined、Null、Boolean、Number 和 String 型。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。

- -

在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。ECMAScript 打破了这一传统。

- -

如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。如下图所示:

- -存储在堆和栈中的原始值和引用值 - -
- - -
-

原始类型

- -

如前所述,ECMAScript 有 5 种原始类型(primitive type),即 Undefined、Null、Boolean、Number 和 String。ECMA-262 把术语类型(type)定义为值的一个集合,每种原始类型定义了它包含的值的范围及其字面量表示形式。

- -

ECMAScript 提供了 typeof 运算符来判断一个值是否在某种类型的范围内。可以用这种运算符判断一个值是否表示一种原始类型:如果它是原始类型,还可以判断它表示哪种原始类型。

- -

在稍后的章节,我们将为您深入讲解 ECMAScript 的原始类型和引用类型。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/关系运算符.html b/app/src/main/assets/help/w3c/关系运算符.html deleted file mode 100644 index a6373b72..00000000 --- a/app/src/main/assets/help/w3c/关系运算符.html +++ /dev/null @@ -1,91 +0,0 @@ -
- -

ECMAScript 关系运算符

- -
- -
- -
-

关系运算符执行的是比较运算。每个关系运算符都返回一个布尔值。

-
- -
-

常规比较方式

- -

关系运算符小于、大于、小于等于和大于等于执行的是两个数的比较运算,比较方式与算术比较运算相同。

- -

每个关系运算符都返回一个布尔值:

- -
-var bResult1 = 2 > 1	//true
-var bResult2 = 2 < 1	//false
-
- -

不过,对两个字符串应用关系运算符,它们的行为则不同。许多人认为小于表示“在字母顺序上靠前”,大于表示“在字母顺序上靠后”,但事实并非如此。对于字符串,第一个字符串中每个字符的代码都与会第二个字符串中对应位置的字符的代码进行数值比较。完成这种比较操作后,返回一个 Boolean 值。问题在于大写字母的代码都小于小写字母的代码,这意味这着可能会遇到下列情况:

- -
-var bResult = "Blue" < "alpha";
-alert(bResult);	//输出 true
-
- -

在上面的例子中,字符串 "Blue" 小于 "alpha",因为字母 B 的字符代码是 66,字母 a 的字符代码是 97。要强制性得到按照真正的字母顺序比较的结果,必须把两个数转换成相同的大小写形式(全大写或全小写的),然后再进行比较:

- -
-var bResult = "Blue".toLowerCase() < "alpha".toLowerCase();
-alert(bResult);	//输出 false
-
- -

把两个运算数都转换成小写,确保了正确识别出 "alpha" 在字母顺序上位于 "Blue" 之前。

-
- - -
-

比较数字和字符串

- -

另一种棘手的状况发生在比较两个字符串形式的数字时,比如:

- -
-var bResult = "25" < "3";
-alert(bResult);	//输出 "true"
-
- -

上面这段代码比较的是字符串 "25" 和 "3"。两个运算数都是字符串,所以比较的是它们的字符代码("2" 的字符代码是 50,"3" 的字符代码是 51)。

- -

不过,如果把某个运算数该为数字,那么结果就有趣了:

- -
-var bResult = "25" < 3;
-alert(bResult);	//输出 "false"
-
- -

这里,字符串 "25" 将被转换成数字 25,然后与数字 3 进行比较,结果不出所料。

- -

无论何时比较一个数字和一个字符串,ECMAScript 都会把字符串转换成数字,然后按照数字顺序比较它们。

- -

不过,如果字符串不能转换成数字又该如何呢?考虑下面的例子:

- -
-var bResult = "a" < 3;
-alert(bResult);
-
- -

你能预料到这段代码输出什么吗?字母 "a" 不能转换成有意义的数字。不过,如果对它调用 parseInt() 方法,返回的是 NaN。根据规则,任何包含 NaN 的关系运算符都要返回 false,因此这段代码也输出 false:

- -
-var bResult = "a" >= 3;
-alert(bResult);
-
- -

通常,如果小于运算的两个值返回 false,那么大于等于运算必须返回 true,不过如果某个数字是 NaN,情况则非如此。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/关键字.html b/app/src/main/assets/help/w3c/关键字.html deleted file mode 100644 index 63cbb581..00000000 --- a/app/src/main/assets/help/w3c/关键字.html +++ /dev/null @@ -1,60 +0,0 @@ -
- -

ECMAScript 关键字

- -
- -
- -
-

本节提供完整的 ECMAScript 关键字列表。

-
- -
-

ECMAScript 关键字

- -

ECMA-262 定义了 ECMAScript 支持的一套关键字(keyword)

- -

这些关键字标识了 ECMAScript 语句的开头和/或结尾。根据规定,关键字是保留的,不能用作变量名或函数名。

- -

下面是 ECMAScript 关键字的完整列表:

- -
-break
-case
-catch
-continue
-default
-delete
-do
-else
-finally
-for
-function
-if
-in
-instanceof
-new
-return
-switch
-this
-throw
-try
-typeof
-var
-void
-while
-with
-
- -

注意:如果把关键字用作变量名或函数名,可能得到诸如 "Identifier Expected"(应该有标识符、期望标识符)这样的错误消息。

- -
- - -
- -
- - -
diff --git a/app/src/main/assets/help/w3c/函数概述.html b/app/src/main/assets/help/w3c/函数概述.html deleted file mode 100644 index 6e257f4f..00000000 --- a/app/src/main/assets/help/w3c/函数概述.html +++ /dev/null @@ -1,121 +0,0 @@ -
- -

ECMAScript 函数概述

- -
- -
- - -
-

什么是函数?

- -

函数是一组可以随时随地运行的语句。

- -

函数是 ECMAScript 的核心。

- -

函数是由这样的方式进行声明的:关键字 function、函数名、一组参数,以及置于括号中的待执行代码。

- -

函数的基本语法是这样的:

- -
function functionName(arg0, arg1, ... argN) {
-  statements
-}
-
- -

例如:

- -
-function sayHi(sName, sMessage) {
-  alert("Hello " + sName + sMessage);
-}
-
-
- - -
-

如何调用函数?

- -

函数可以通过其名字加上括号中的参数进行调用,如果有多个参数。

- -

如果您想调用上例中的那个函数,可以使用如下的代码:

- -
sayHi("David", " Nice to meet you!")
- -

调用上面的函数 sayHi() 会生成一个警告窗口。您可以亲自试一试这个例子

-
- - -
-

函数如何返回值?

- -

函数 sayHi() 未返回值,不过不必专门声明它(像在 Java 中使用 void 那样)。

- -

即使函数确实有值,也不必明确地声明它。该函数只需要使用 return 运算符后跟要返回的值即可。

- -
-function sum(iNum1, iNum2) {
-  return iNum1 + iNum2;
-}
-
- -

下面的代码把 sum 函数返回的值赋予一个变量:

- -
-var iResult = sum(1,1);
-alert(iResult);	//输出 "2"
-
- -

另一个重要概念是,与在 Java 中一样,函数在执行过 return 语句后立即停止代码。因此,return 语句后的代码都不会被执行。

- -

例如,在下面的代码中,alert 窗口就不会显示出来:

- -
-function sum(iNum1, iNum2) {
-  return iNum1 + iNum2;
-  alert(iNum1 + iNum2);
-}
-
- -

一个函数中可以有多个 return 语句,如下所示:

- -
-function diff(iNum1, iNum2) {
-  if (iNum1 > iNum2) {
-    return iNum1 - iNum2;
-  } else {
-    return iNum2 - iNum1;
-  }
-}
-
- -

上面的函数用于返回两个数的差。要实现这一点,必须用较大的数减去较小的数,因此用 if 语句决定执行哪个 return 语句。

- -

如果函数无返回值,那么可以调用没有参数的 return 运算符,随时退出函数。

- -

例如:

- -
-function sayHi(sMessage) {
-  if (sMessage == "bye") {
-    return;
-  }
-
-  alert(sMessage);
-}
-
- -

这段代码中,如果 sMessage 等于 "bye",就永远不显示警告框。

- -

注释:如果函数无明确的返回值,或调用了没有参数的 return 语句,那么它真正返回的值是 undefined。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/加性运算符.html b/app/src/main/assets/help/w3c/加性运算符.html deleted file mode 100644 index 91664917..00000000 --- a/app/src/main/assets/help/w3c/加性运算符.html +++ /dev/null @@ -1,88 +0,0 @@ -
- -

ECMAScript 加性运算符

- -
- -
- - -
-

在多数程序设计语言中,加性运算符(即加号或减号)通常是最简单的数学运算符。

-

在 ECMAScript 中,加性运算符有大量的特殊行为。

-
- - -
-

加法运算符

- -

法运算符由加号(+)表示:

- -
var iResult = 1 + 2
- -

与乘性运算符一样,在处理特殊值时,ECMAScript 中的加法也有一些特殊行为:

- -
    -
  • 某个运算数是 NaN,那么结果为 NaN。
  • -
  • -Infinity 加 -Infinity,结果为 -Infinity。
  • -
  • Infinity 加 -Infinity,结果为 NaN。
  • -
  • +0 加 +0,结果为 +0。
  • -
  • -0 加 +0,结果为 +0。
  • -
  • -0 加 -0,结果为 -0。
  • -
- -

不过,如果某个运算数是字符串,那么采用下列规则:

- -
    -
  • 如果两个运算数都是字符串,把第二个字符串连接到第一个上。
  • -
  • 如果只有一个运算数是字符串,把另一个运算数转换成字符串,结果是两个字符串连接成的字符串。
  • -
- -

例如:

- -
-var result = 5 + 5;	//两个数字
-alert(result);		//输出 "10"
-var result2 = 5 + "5";	//一个数字和一个字符串
-alert(result);		//输出 "55"
-
- -

这段代码说明了加法运算符的两种模式之间的差别。正常情况下,5+5 等于 10(原始数值),如上述代码中前两行所示。不过,如果把一个运算数改为字符串 "5",那么结果将变为 "55"(原始的字符串值),因为另一个运算数也会被转换为字符串。

- -

注意:为了避免 JavaScript 中的一种常见错误,在使用加法运算符时,一定要仔细检查运算数的数据类型。

-
- - -
-

减法运算符

- -

减法运算符(-),也是一个常用的运算符:

- -
var iResult = 2 - 1;
- -

与加法运算符一样,在处理特殊值时,减法运算符也有一些特殊行为:

- -
    -
  • 某个运算数是 NaN,那么结果为 NaN。
  • -
  • Infinity 减 Infinity,结果为 NaN。
  • -
  • -Infinity 减 -Infinity,结果为 NaN。
  • -
  • Infinity 减 -Infinity,结果为 Infinity。
  • -
  • -Infinity 减 Infinity,结果为 -Infinity。
  • -
  • +0 减 +0,结果为 +0。
  • -
  • -0 减 -0,结果为 -0。
  • -
  • +0 减 -0,结果为 +0。
  • -
  • 某个运算符不是数字,那么结果为 NaN。
  • -
- -

注释:如果运算数都是数字,那么执行常规的减法运算,并返回结果。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/原始类型.html b/app/src/main/assets/help/w3c/原始类型.html deleted file mode 100644 index 85696bc3..00000000 --- a/app/src/main/assets/help/w3c/原始类型.html +++ /dev/null @@ -1,286 +0,0 @@ -
- -

ECMAScript 原始类型

- -
- -
- - -
-

ECMAScript 有 5 种原始类型(primitive type),即 Undefined、Null、Boolean、Number 和 String。

-
- - -
-

typeof 运算符

- -

typeof 运算符有一个参数,即要检查的变量或值。例如:

- -
-var sTemp = "test string";
-alert (typeof sTemp);    //输出 "string"
-alert (typeof 86);    //输出 "number"
-
- -

对变量或值调用 typeof 运算符将返回下列值之一:

- -
    -
  • undefined - 如果变量是 Undefined 类型的
  • -
  • boolean - 如果变量是 Boolean 类型的
  • -
  • number - 如果变量是 Number 类型的
  • -
  • string - 如果变量是 String 类型的
  • -
  • object - 如果变量是一种引用类型或 Null 类型的
  • -
- -

注释:您也许会问,为什么 typeof 运算符对于 null 值会返回 "Object"。这实际上是 JavaScript 最初实现中的一个错误,然后被 ECMAScript 沿用了。现在,null 被认为是对象的占位符,从而解释了这一矛盾,但从技术上来说,它仍然是原始值。

- -
- - -
-

Undefined 类型

- -

如前所述,Undefined 类型只有一个值,即 undefined。当声明的变量未初始化时,该变量的默认值是 undefined。

- -
var oTemp;
- -

前面一行代码声明变量 oTemp,没有初始值。该变量将被赋予值 undefined,即 undefined 类型的字面量。可以用下面的代码段测试该变量的值是否等于 undefined:

- -
-var oTemp;
-alert(oTemp == undefined);
-
- -

这段代码将显示 "true",说明这两个值确实相等。还可以用 typeof 运算符显示该变量的值是 undefined:

- -
-var oTemp;
-alert(typeof oTemp); //输出 "undefined"
-
- -

提示:值 undefined 并不同于未定义的值。但是,typeof 运算符并不真正区分这两种值。考虑下面的代码:

- -
-var oTemp;
-
-alert(typeof oTemp);  //输出 "undefined"
-alert(typeof oTemp2);  //输出 "undefined"
-
- -

前面的代码对两个变量输出的都是 "undefined",即使只有变量 oTemp2 从未被声明过。如果对 oTemp2 使用除 typeof 之外的其他运算符的话,会引起错误,因为其他运算符只能用于已声明的变量上。

- -

例如,下面的代码将引发错误:

- -
-var oTemp;
-alert(oTemp2 == undefined);
-
- -

当函数无明确返回值时,返回的也是值 "undefined",如下所示:

- -
-function testFunc() {
-}
-
-alert(testFunc() == undefined);  //输出 "true"
-
-
- - -
-

Null 类型

- -

另一种只有一个值的类型是 Null,它只有一个专用值 null,即它的字面量。值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的。

- -
-alert(null == undefined);  //输出 "true"
-
- -

尽管这两个值相等,但它们的含义不同。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示尚未存在的对象(在讨论 typeof 运算符时,简单地介绍过这一点)。如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null。

-
- - -
-

Boolean 类型

- -

Boolean 类型是 ECMAScript 中最常用的类型之一。它有两个值 true 和 false (即两个 Boolean 字面量)。

- -

即使 false 不等于 0,0 也可以在必要时被转换成 false,这样在 Boolean 语句中使用两者都是安全的。

- -
-var bFound = true;
-var bLost = false;
-
-
- - -
-

Number 类型

- -

ECMA-262 中定义的最特殊的类型是 Number 类型。这种类型既可以表示 32 位的整数,还可以表示 64 位的浮点数。

- -

直接输入的(而不是从另一个变量访问的)任何数字都被看做 Number 类型的字面量。例如,下面的代码声明了存放整数值的变量,它的值由字面量 86 定义:

- -
var iNum = 86;
- -

八进制数和十六进制数

- -

整数也可以被表示为八进制(以 8 为底)或十六进制(以 16 为底)的字面量。八进制字面量的首数字必须是 0,其后的数字可以是任何八进制数字(0-7),如下面的代码所示:

-
var iNum = 070;  //070 等于十进制的 56
- -

要创建十六进制的字面量,首位数字必须为 0,后面接字母 x,然后是任意的十六进制数字(0 到 9 和 A 到 F)。这些字母可以是大写的,也可以是小写的。例如:

-
-var iNum = 0x1f;  //0x1f 等于十进制的 31
-var iNum = 0xAB;  //0xAB 等于十进制的 171
-
- -

提示:尽管所有整数都可以表示为八进制或十六进制的字面量,但所有数学运算返回的都是十进制结果。

- -

浮点数

- -

要定义浮点值,必须包括小数点和小数点后的一位数字(例如,用 1.0 而不是 1)。这被看作浮点数字面量。例如:

-
var fNum = 5.0;
- -

对于浮点字面量的有趣之处在于,用它进行计算前,真正存储的是字符串。

- -

科学计数法

-

对于非常大或非常小的数,可以用科学计数法表示浮点数,可以把一个数表示为数字(包括十进制数字)加 e(或 E),后面加乘以 10 的倍数。例如:

- -
var fNum = 5.618e7
- -

该符号表示的是数 56180000。把科学计数法转化成计算式就可以得到该值:5.618 x 107

- -

也可以用科学计数法表示非常小的数,例如 0.00000000000000008 可以表示为 8-e17(这里,10 被升到 -17 次冥,意味着需要被 10 除 17 次)。ECMAScript 默认把具有 6 个或 6 个以上前导 0 的浮点数转换成科学计数法。

- -

提示:也可用 64 位 IEEE 754 形式存储浮点值,这意味着十进制值最多可以有 17 个十进制位。17 位之后的值将被裁去,从而造成一些小的数学误差。

- - -

特殊的 Number 值

- -

几个特殊值也被定义为 Number 类型。前两个是 Number.MAX_VALUE 和 Number.MIN_VALUE,它们定义了 Number 值集合的外边界。所有 ECMAScript 数都必须在这两个值之间。不过计算生成的数值结果可以不落在这两个值之间。

- -

当计算生成的数大于 Number.MAX_VALUE 时,它将被赋予值 Number.POSITIVE_INFINITY,意味着不再有数字值。同样,生成的数值小于 Number.MIN_VALUE 的计算也会被赋予值 Number.NEGATIVE_INFINITY,也意味着不再有数字值。如果计算返回的是无穷大值,那么生成的结果不能再用于其他计算。

- -

事实上,有专门的值表示无穷大,(如你猜到的)即 Infinity。Number.POSITIVE_INFINITY 的值为 Infinity。Number.NEGATIVE_INFINITY 的值为 -Infinity。

- -

由于无穷大数可以是正数也可以是负数,所以可用一个方法判断一个数是否是有穷的(而不是单独测试每个无穷数)。可以对任何数调用 isFinite() 方法,以确保该数不是无穷大。例如:

- -
-var iResult = iNum * some_really_large_number;
-
-if (isFinite(iResult)) {
-    alert("finite");
-}
-
-else {
-    alert("infinite");
-}
-
- -

最后一个特殊值是 NaN,表示非数(Not a Number)。NaN 是个奇怪的特殊值。一般说来,这种情况发生在类型(String、Boolean 等)转换失败时。例如,要把单词 blue 转换成数值就会失败,因为没有与之等价的数值。与无穷大一样,NaN 也不能用于算术计算。NaN 的另一个奇特之处在于,它与自身不相等,这意味着下面的代码将返回 false:

- -
alert(NaN == NaN);  //输出 "false"
- -

出于这个原因,不推荐使用 NaN 值本身。函数 isNaN() 会做得相当好:

- -
-alert(isNaN("blue"));  //输出 "true"
-alert(isNaN("666"));  //输出 "false"
-
- -
- - -
-

String 类型

- -

String 类型的独特之处在于,它是唯一没有固定大小的原始类型。可以用字符串存储 0 或更多的 Unicode 字符,有 16 位整数表示(Unicode 是一种国际字符集,本教程后面将讨论它)。

- -

字符串中每个字符都有特定的位置,首字符从位置 0 开始,第二个字符在位置 1,依此类推。这意味着字符串中的最后一个字符的位置一定是字符串的长度减 1:

- -字符串的长度和字符的位置 - -

字符串字面量是由双引号(")或单引号(')声明的。而 Java 则是用双引号声明字符串,用单引号声明字符。但是由于 ECMAScript 没有字符类型,所以可使用这两种表示法中的任何一种。例如,下面的两行代码都有效:

- -
-var sColor1 = "red";
-var sColor2 = 'red';
-
- -

String 类型还包括几种字符字面量,Java、C 和 Perl 的开发者应该对此非常熟悉。

- -

下面列出了 ECMAScript 的字符字面量:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字面量含义
\n换行
\t制表符
\b空格
\r回车
\f换页符
\\反斜杠
\'单引号
\"双引号
\0nnn八进制代码 nnn 表示的字符(n 是 0 到 7 中的一个八进制数字)
\xnn十六进制代码 nn 表示的字符(n 是 0 到 F 中的一个十六进制数字)
\unnnn十六进制代码 nnnn 表示的 Unicode 字符(n 是 0 到 F 中的一个十六进制数字)
-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/变量.html b/app/src/main/assets/help/w3c/变量.html deleted file mode 100644 index db3c3eaf..00000000 --- a/app/src/main/assets/help/w3c/变量.html +++ /dev/null @@ -1,191 +0,0 @@ -
- -

ECMAScript 变量

- -
- -
- -
-

请使用 var 运算符声明变量。

-

变量名需要遵守一些简单的规则。

-
- - -
-

声明变量

- -

在上一节中我们讲解过,ECMAScript 中的变量是用 var 运算符(variable 的缩写)加变量名定义的。例如:

- -
var test = "hi";
- -

在这个例子中,声明了变量 test,并把它的值初始化为 "hi"(字符串)。由于 ECMAScript 是弱类型的,所以解释程序会为 test 自动创建一个字符串值,无需明确的类型声明

- -

还可以用一个 var 语句定义两个或多个变量:

- -
var test1 = "hi", test2 = "hello";
- -

前面的代码定义了变量 test1,初始值为 "hi",还定义了变量 test2,初始值为 "hello"。

- -

不过用同一个 var 语句定义的变量不必具有相同的类型,如下所示:

- -
var test = "hi", age = 25;
- -

这个例子除了(再次)定义 test 外,还定义了 age,并把它初始化为 25。即使 test 和 age 属于两种不同的数据类型,在 ECMAScript 中这样定义也是完全合法的。

- -

与 Java 不同,ECMAScript 中的变量并不一定要初始化(它们是在幕后初始化的,将在后面讨论这一点)。因此,下面这一行代码也是有效的:

- -
var test;
- -

此外,与 Java 不同的还有变量可以存放不同类型的值。这是弱类型变量的优势。例如,可以把变量初始化为字符串类型的值,之后把它设置为数字值,如下所示:

- -
-var test = "hi";
-alert(test);
-test = 55;
-alert(test);
-
- -

这段代码将毫无问题地输出字符串值和数字值。但是,如前所述,使用变量时,好的编码习惯是始终存放相同类型的值。

- -
- - -
-

命名变量

- -

变量名需要遵守两条简单的规则:

- -
    -
  • 第一个字符必须是字母、下划线(_)或美元符号($)
  • -
  • 余下的字符可以是下划线、美元符号或任何字母或数字字符
  • -
- -

下面的变量都是合法的:

- -
-var test;
-var $test;
-var $1;
-var _$te$t2;
-
-
- - -
-

著名的变量命名规则

- -

只是因为变量名的语法正确,并不意味着就该使用它们。变量还应遵守以下某条著名的命名规则:

- -

Camel 标记法

-

首字母是小写的,接下来的字母都以大写字符开头。例如:

-
-var myTestValue = 0, mySecondValue = "hi";
-
- -

Pascal 标记法

-

首字母是大写的,接下来的字母都以大写字符开头。例如:

-
-var MyTestValue = 0, MySecondValue = "hi";
-
- -

匈牙利类型标记法

-

在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串,如下所示“

-
-var iMyTestValue = 0, sMySecondValue = "hi";
-
- -

本教程采用了这些前缀,以使示例代码更易阅读:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
类型前缀示例
数组aaValues
布尔型bbFound
浮点型(数字)ffValue
函数fnfnMethod
整型(数字)iiValue
对象ooType
正则表达式rerePattern
字符串ssValue
变型(可以是任何类型)vvValue
-
- - -
-

变量声明不是必须的

- -

ECMAScript 另一个有趣的方面(也是与大多数程序设计语言的主要区别),是在使用变量之前不必声明。例如:

- -
-var sTest = "hello ";
-sTest2 = sTest + "world";
-alert(sTest2);
-
- -

在上面的代码中,首先,sTest 被声明为字符串类型的值 "hello"。接下来的一行,用变量 sTest2 把 sTest 与字符串 "world" 连在一起。变量 sTest2 并没有用 var 运算符定义,这里只是插入了它,就像已经声明过它一样。

- -

ECMAScript 的解释程序遇到未声明过的标识符时,用该变量名创建一个全局变量,并将其初始化为指定的值。

- -

这是该语言的便利之处,不过如果不能紧密跟踪变量,这样做也很危险。最好的习惯是像使用其他程序设计语言一样,总是声明所有变量。

- -
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/定义类或对象.html b/app/src/main/assets/help/w3c/定义类或对象.html deleted file mode 100644 index f7bf8c4f..00000000 --- a/app/src/main/assets/help/w3c/定义类或对象.html +++ /dev/null @@ -1,455 +0,0 @@ -
- -

ECMAScript 定义类或对象

- -
- -
- - -
-

使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的类和对象。

-

ECMAScript 拥有很多创建对象或类的方法。

-
- - -
-

工厂方式

- -

原始的方式

- -

因为对象的属性可以在对象创建后动态定义,所有许多开发者都在 JavaScript 最初引入时编写类似下面的代码:

- -
-var oCar = new Object;
-oCar.color = "blue";
-oCar.doors = 4;
-oCar.mpg = 25;
-oCar.showColor = function() {
-  alert(this.color);
-};
-
- -

TIY

- -

在上面的代码中,创建对象 car。然后给它设置几个属性:它的颜色是蓝色,有四个门,每加仑油可以跑 25 英里。最后一个属性实际上是指向函数的指针,意味着该属性是个方法。执行这段代码后,就可以使用对象 car。

- -

不过这里有一个问题,就是可能需要创建多个 car 的实例。

- - -

解决方案:工厂方式

- -

要解决该问题,开发者创造了能创建并返回特定类型的对象的工厂函数(factory function)。

- -

例如,函数 createCar() 可用于封装前面列出的创建 car 对象的操作:

- -
-function createCar() {
-  var oTempCar = new Object;
-  oTempCar.color = "blue";
-  oTempCar.doors = 4;
-  oTempCar.mpg = 25;
-  oTempCar.showColor = function() {
-    alert(this.color);
-  };
-  return oTempCar;
-}
-
-var oCar1 = createCar();
-var oCar2 = createCar();
-
- -

TIY

- -

在这里,第一个例子中的所有代码都包含在 createCar() 函数中。此外,还有一行额外的代码,返回 car 对象(oTempCar)作为函数值。调用此函数,将创建新对象,并赋予它所有必要的属性,复制出一个我们在前面说明过的 car 对象。因此,通过这种方法,我们可以很容易地创建 car 对象的两个版本(oCar1 和 oCar2),它们的属性完全一样。

- - -

为函数传递参数

- -

我们还可以修改 createCar() 函数,给它传递各个属性的默认值,而不是简单地赋予属性默认值:

- -
-function createCar(sColor,iDoors,iMpg) {
-  var oTempCar = new Object;
-  oTempCar.color = sColor;
-  oTempCar.doors = iDoors;
-  oTempCar.mpg = iMpg;
-  oTempCar.showColor = function() {
-    alert(this.color);
-  };
-  return oTempCar;
-}
-
-var oCar1 = createCar("red",4,23);
-var oCar2 = createCar("blue",3,25);
-
-oCar1.showColor();		//输出 "red"
-oCar2.showColor();		//输出 "blue"
-
- -

TIY

- -

给 createCar() 函数加上参数,即可为要创建的 car 对象的 color、doors 和 mpg 属性赋值。这使两个对象具有相同的属性,却有不同的属性值。

- - -

在工厂函数外定义对象的方法

- -

虽然 ECMAScript 越来越正式化,但创建对象的方法却被置之不理,且其规范化至今还遭人反对。一部分是语义上的原因(它看起来不像使用带有构造函数 new 运算符那么正规),一部分是功能上的原因。功能原因在于用这种方式必须创建对象的方法。前面的例子中,每次调用函数 createCar(),都要创建新函数 showColor(),意味着每个对象都有自己的 showColor() 版本。而事实上,每个对象都共享同一个函数。

- -

有些开发者在工厂函数外定义对象的方法,然后通过属性指向该方法,从而避免这个问题:

- -
-function showColor() {
-  alert(this.color);
-}
-
-function createCar(sColor,iDoors,iMpg) {
-  var oTempCar = new Object;
-  oTempCar.color = sColor;
-  oTempCar.doors = iDoors;
-  oTempCar.mpg = iMpg;
-  oTempCar.showColor = showColor;
-  return oTempCar;
-}
-
-var oCar1 = createCar("red",4,23);
-var oCar2 = createCar("blue",3,25);
-
-oCar1.showColor();		//输出 "red"
-oCar2.showColor();		//输出 "blue"
-
- -

TIY

- -

在上面这段重写的代码中,在函数 createCar() 之前定义了函数 showColor()。在 createCar() 内部,赋予对象一个指向已经存在的 showColor() 函数的指针。从功能上讲,这样解决了重复创建函数对象的问题;但是从语义上讲,该函数不太像是对象的方法。

- -

所有这些问题都引发了开发者定义的构造函数的出现。

-
- - -
-

构造函数方式

- -

创建构造函数就像创建工厂函数一样容易。第一步选择类名,即构造函数的名字。根据惯例,这个名字的首字母大写,以使它与首字母通常是小写的变量名分开。除了这点不同,构造函数看起来很像工厂函数。请考虑下面的例子:

- -
-function Car(sColor,iDoors,iMpg) {
-  this.color = sColor;
-  this.doors = iDoors;
-  this.mpg = iMpg;
-  this.showColor = function() {
-    alert(this.color);
-  };
-}
-
-var oCar1 = new Car("red",4,23);
-var oCar2 = new Car("blue",3,25);
-
- -

TIY

- -

下面为您解释上面的代码与工厂方式的差别。首先在构造函数内没有创建对象,而是使用 this 关键字。使用 new 运算符构造函数时,在执行第一行代码前先创建一个对象,只有用 this 才能访问该对象。然后可以直接赋予 this 属性,默认情况下是构造函数的返回值(不必明确使用 return 运算符)。

- -

现在,用 new 运算符和类名 Car 创建对象,就更像 ECMAScript 中一般对象的创建方式了。

- -

你也许会问,这种方式在管理函数方面是否存在于前一种方式相同的问题呢?是的。

- -

就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂函数相似,也可以用外部函数重写构造函数,同样地,这么做语义上无任何意义。这正是下面要讲的原型方式的优势所在。

-
- - -
-

原型方式

- -

该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。

- -

这里,首先用空构造函数来设置类名。然后所有的属性和方法都被直接赋予 prototype 属性。我们重写了前面的例子,代码如下:

- -
-function Car() {
-}
-
-Car.prototype.color = "blue";
-Car.prototype.doors = 4;
-Car.prototype.mpg = 25;
-Car.prototype.showColor = function() {
-  alert(this.color);
-};
-
-var oCar1 = new Car();
-var oCar2 = new Car();
-
- -

TIY

- -

在这段代码中,首先定义构造函数(Car),其中无任何代码。接下来的几行代码,通过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。调用 new Car() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Car 实例存放的都是指向 showColor() 函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面两种方式存在的问题。

- -

此外,使用这种方式,还能用 instanceof 运算符检查给定变量指向的对象的类型。因此,下面的代码将输出 TRUE:

- -
alert(oCar1 instanceof Car);	//输出 "true"
- - -

原型方式的问题

- -

原型方式看起来是个不错的解决方案。遗憾的是,它并不尽如人意。

- -

首先,这个构造函数没有参数。使用原型方式,不能通过给构造函数传递参数来初始化属性的值,因为 Car1 和 Car2 的 color 属性都等于 "blue",doors 属性都等于 4,mpg 属性都等于 25。这意味着必须在对象创建后才能改变属性的默认值,这点很令人讨厌,但还没完。真正的问题出现在属性指向的是对象,而不是函数时。函数共享不会造成问题,但对象却很少被多个实例共享。请思考下面的例子:

- -
-function Car() {
-}
-
-Car.prototype.color = "blue";
-Car.prototype.doors = 4;
-Car.prototype.mpg = 25;
-Car.prototype.drivers = new Array("Mike","John");
-Car.prototype.showColor = function() {
-  alert(this.color);
-};
-
-var oCar1 = new Car();
-var oCar2 = new Car();
-
-oCar1.drivers.push("Bill");
-
-alert(oCar1.drivers);	//输出 "Mike,John,Bill"
-alert(oCar2.drivers);	//输出 "Mike,John,Bill"
-
- -

TIY

- -

上面的代码中,属性 drivers 是指向 Array 对象的指针,该数组中包含两个名字 "Mike" 和 "John"。由于 drivers 是引用值,Car 的两个实例都指向同一个数组。这意味着给 oCar1.drivers 添加值 "Bill",在 oCar2.drivers 中也能看到。输出这两个指针中的任何一个,结果都是显示字符串 "Mike,John,Bill"。

- -

由于创建对象时有这么多问题,你一定会想,是否有种合理的创建对象的方法呢?答案是有,需要联合使用构造函数和原型方式。

-
- - -
-

混合的构造函数/原型方式

- -

联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象。这种概念非常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。结果是,所有函数都只创建一次,而每个对象都具有自己的对象属性实例。

- -

我们重写了前面的例子,代码如下:

- -
-function Car(sColor,iDoors,iMpg) {
-  this.color = sColor;
-  this.doors = iDoors;
-  this.mpg = iMpg;
-  this.drivers = new Array("Mike","John");
-}
-
-Car.prototype.showColor = function() {
-  alert(this.color);
-};
-
-var oCar1 = new Car("red",4,23);
-var oCar2 = new Car("blue",3,25);
-
-oCar1.drivers.push("Bill");
-
-alert(oCar1.drivers);	//输出 "Mike,John,Bill"
-alert(oCar2.drivers);	//输出 "Mike,John"
-
- -

TIY

- -

现在就更像创建一般对象了。所有的非函数属性都在构造函数中创建,意味着又能够用构造函数的参数赋予属性默认值了。因为只创建 showColor() 函数的一个实例,所以没有内存浪费。此外,给 oCar1 的 drivers 数组添加 "Bill" 值,不会影响到 oCar2 的数组,所以输出这些数组的值时,oCar1.drivers 显示的是 "Mike,John,Bill",而 oCar2.drivers 显示的是 "Mike,John"。因为使用了原型方式,所以仍然能利用 instanceof 运算符来判断对象的类型。

- -

这种方式是 ECMAScript 采用的主要方式,它具有其他方式的特性,却没有他们的副作用。不过,有些开发者仍觉得这种方法不够完美。

-
- - -
-

动态原型方法

- -

对于习惯使用其他语言的开发者来说,使用混合的构造函数/原型方式感觉不那么和谐。毕竟,定义类时,大多数面向对象语言都对属性和方法进行了视觉上的封装。请考虑下面的 Java 类:

- -
-class Car {
-  public String color = "blue";
-  public int doors = 4;
-  public int mpg = 25;
-
-  public Car(String color, int doors, int mpg) {
-    this.color = color;
-    this.doors = doors;
-    this.mpg = mpg;
-  }
-  
-  public void showColor() {
-    System.out.println(color);
-  }
-}
-
- -

Java 很好地打包了 Car 类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内部找属性,在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风格。

- -

动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的 Car 类:

- -
-function Car(sColor,iDoors,iMpg) {
-  this.color = sColor;
-  this.doors = iDoors;
-  this.mpg = iMpg;
-  this.drivers = new Array("Mike","John");
-  
-  if (typeof Car._initialized == "undefined") {
-    Car.prototype.showColor = function() {
-      alert(this.color);
-    };
-	
-    Car._initialized = true;
-  }
-}
-
- -

TIY

- -

直到检查 typeof Car._initialized 是否等于 "undefined" 之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把 Car._initialized 设置为 true。如果这个值定义了(它的值为 true 时,typeof 的值为 Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,传统的 OOP 开发者会高兴地发现,这段代码看起来更像其他语言中的类定义了。

-
- - -
-

混合工厂方式

- -

这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。

- -

这段代码看起来与工厂函数非常相似:

- -
-function Car() {
-  var oTempCar = new Object;
-  oTempCar.color = "blue";
-  oTempCar.doors = 4;
-  oTempCar.mpg = 25;
-  oTempCar.showColor = function() {
-    alert(this.color);
-  };
-
-  return oTempCar;
-}
-
- -

TIY

- -

与经典方式不同,这种方式使用 new 运算符,使它看起来像真正的构造函数:

- -
var car = new Car();
- -

由于在 Car() 构造函数内部调用了 new 运算符,所以将忽略第二个 new 运算符(位于构造函数之外),在构造函数内部创建的对象被传递回变量 car。

- -

这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非万不得已,还是避免使用这种方式。

-
- - -
-

采用哪种方式

- -

如前所述,目前使用最广泛的是混合的构造函数/原型方式。此外,动态原始方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。

-
- - -
-

实例

- -

对象令人感兴趣的一点是用它们解决问题的方式。ECMAScript 中最常见的一个问题是字符串连接的性能。与其他语言类似,ECMAScript 的字符串是不可变的,即它们的值不能改变。请考虑下面的代码:

- -
-var str = "hello ";
-str += "world";
-
- -

实际上,这段代码在幕后执行的步骤如下:

- -
    -
  1. 创建存储 "hello " 的字符串。
  2. -
  3. 创建存储 "world" 的字符串。
  4. -
  5. 创建存储连接结果的字符串。
  6. -
  7. 把 str 的当前内容复制到结果中。
  8. -
  9. 把 "world" 复制到结果中。
  10. -
  11. 更新 str,使它指向结果。
  12. -
- -

每次完成字符串连接都会执行步骤 2 到 6,使得这种操作非常消耗资源。如果重复这一过程几百次,甚至几千次,就会造成性能问题。解决方法是用 Array 对象存储字符串,然后用 join() 方法(参数是空字符串)创建最后的字符串。想象用下面的代码代替前面的代码:

- -
-var arr = new Array();
-arr[0] = "hello ";
-arr[1] = "world";
-var str = arr.join("");
-
- -

这样,无论数组中引入多少字符串都不成问题,因为只在调用 join() 方法时才会发生连接操作。此时,执行的步骤如下:

- -
    -
  1. 创建存储结果的字符串
  2. -
  3. 把每个字符串复制到结果中的合适位置
  4. -
- -

虽然这种解决方案很好,但还有更好的方法。问题是,这段代码不能确切反映出它的意图。要使它更容易理解,可以用 StringBuffer 类打包该功能:

- -
-function StringBuffer () {
-  this._strings_ = new Array();
-}
-
-StringBuffer.prototype.append = function(str) {
-  this._strings_.push(str);
-};
-
-StringBuffer.prototype.toString = function() {
-  return this._strings_.join("");
-};
-
- -

这段代码首先要注意的是 strings 属性,本意是私有属性。它只有两个方法,即 append() 和 toString() 方法。append() 方法有一个参数,它把该参数附加到字符串数组中,toString() 方法调用数组的 join 方法,返回真正连接成的字符串。要用 StringBuffer 对象连接一组字符串,可以用下面的代码:

- -
-var buffer = new StringBuffer ();
-buffer.append("hello ");
-buffer.append("world");
-var result = buffer.toString();
-
- -

TIY

- -

可用下面的代码测试 StringBuffer 对象和传统的字符串连接方法的性能:

- -
-var d1 = new Date();
-var str = "";
-for (var i=0; i < 10000; i++) {
-    str += "text";
-}
-var d2 = new Date();
-
-document.write("Concatenation with plus: "
- + (d2.getTime() - d1.getTime()) + " milliseconds");
-
-var buffer = new StringBuffer();
-d1 = new Date();
-for (var i=0; i < 10000; i++) {
-    buffer.append("text");
-}
-var result = buffer.toString();
-d2 = new Date();
-
-document.write("<br />Concatenation with StringBuffer: "
- + (d2.getTime() - d1.getTime()) + " milliseconds");
-
- -

TIY

- -

这段代码对字符串连接进行两个测试,第一个使用加号,第二个使用 StringBuffer 类。每个操作都连接 10000 个字符串。日期值 d1 和 d2 用于判断完成操作需要的时间。请注意,创建 Date 对象时,如果没有参数,赋予对象的是当前的日期和时间。要计算连接操作历经多少时间,把日期的毫秒表示(用 getTime() 方法的返回值)相减即可。这是衡量 JavaScript 性能的常见方法。该测试的结果可以帮助您比较使用 StringBuffer 类与使用加号的效率差异。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/对象作用域.html b/app/src/main/assets/help/w3c/对象作用域.html deleted file mode 100644 index e5d1fd00..00000000 --- a/app/src/main/assets/help/w3c/对象作用域.html +++ /dev/null @@ -1,148 +0,0 @@ -
- -

ECMAScript 对象作用域

- -
- -
- - -
-

作用域指的是变量的适用范围。

-
- - -
-

公用、私有和受保护作用域

- -

概念

- -

在传统的面向对象程序设计中,主要关注于公用和私有作用域。公用作用域中的对象属性可以从对象外部访问,即开发者创建对象的实例后,就可使用它的公用属性。而私有作用域中的属性只能在对象内部访问,即对于外部世界来说,这些属性并不存在。这意味着如果类定义了私有属性和方法,则它的子类也不能访问这些属性和方法。

- -

受保护作用域也是用于定义私有的属性和方法,只是这些属性和方法还能被其子类访问。

- -

ECMAScript 只有公用作用域

- -

对 ECMAScript 讨论上面这些作用域几乎毫无意义,因为 ECMAScript 中只存在一种作用域 - 公用作用域。ECMAScript 中的所有对象的所有属性和方法都是公用的。因此,定义自己的类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的!

- -

建议性的解决方法

- -

许多开发者都在网上提出了有效的属性作用域模式,解决了 ECMAScript 的这种问题。

- -

由于缺少私有作用域,开发者确定了一个规约,说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线:

- -
obj._color_ = "blue";
- -

这段代码中,属性 color 是私有的。注意,下划线并不改变属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作私有的。

- -

有些开发者还喜欢用单下划线说明私有成员,例如:obj._color。

-
- - -
-

静态作用域

- -

静态作用域定义的属性和方法任何时候都能从同一位置访问。在 Java 中,类可具有属性和方法,无需实例化该类的对象,即可访问这些属性和方法,例如 java.net.URLEncoder 类,它的函数 encode() 就是静态方法。

- -

ECMAScript 没有静态作用域

- -

严格来说,ECMAScript 并没有静态作用域。不过,它可以给构造函数提供属性和方法。还记得吗,构造函数只是函数。函数是对象,对象可以有属性和方法。例如:

- -
-function sayHello() {
-  alert("hello");
-}
-
-sayHello.alternate = function() {
-  alert("hi");
-}
-
-sayHello();		//输出 "hello"
-sayHello.alternate();	//输出 "hi"
-
- -

TIY

- -

这里,方法 alternate() 实际上是函数 sayHello 的方法。可以像调用常规函数一样调用 sayHello() 输出 "hello",也可以调用 sayHello.alternate() 输出 "hi"。即使如此,alternate() 也是 sayHello() 公用作用域中的方法,而不是静态方法。

-
- - -
-

关键字 this

- -

this 的功能

- -

在 ECMAScript 中,要掌握的最重要的概念之一是关键字 this 的用法,它用在对象的方法中。关键字 this 总是指向调用该方法的对象,例如:

- -
-var oCar = new Object;
-oCar.color = "red";
-oCar.showColor = function() {
-  alert(this.color);
-};
-
-oCar.showColor();		//输出 "red"
-
- -

TIY

- -

在上面的代码中,关键字 this 用在对象的 showColor() 方法中。在此环境中,this 等于 oCar。下面的代码与上面的代码的功能相同:

- -
-var oCar = new Object;
-oCar.color = "red";
-oCar.showColor = function() {
-  alert(oCar.color);
-};
-
-oCar.showColor();		//输出 "red"
-
- -

TIY

- - -

使用 this 的原因

- -

为什么使用 this 呢?因为在实例化对象时,总是不能确定开发者会使用什么样的变量名。使用 this,即可在任何多个地方重用同一个函数。请思考下面的例子:

- -
-function showColor() {
-  alert(this.color);
-};
-
-var oCar1 = new Object;
-oCar1.color = "red";
-oCar1.showColor = showColor;
-
-var oCar2 = new Object;
-oCar2.color = "blue";
-oCar2.showColor = showColor;
-
-oCar1.showColor();		//输出 "red"
-oCar2.showColor();		//输出 "blue"
-
- -

TIY

- -

在上面的代码中,首先用 this 定义函数 showColor(),然后创建两个对象(oCar1 和 oCar2),一个对象的 color 属性被设置为 "red",另一个对象的 color 属性被设置为 "blue"。两个对象都被赋予了属性 showColor,指向原始的 showColor () 函数(注意这里不存在命名问题,因为一个是全局函数,而另一个是对象的属性)。调用每个对象的 showColor(),oCar1 输出是 "red",而 oCar2 的输出是 "blue"。这是因为调用 oCar1.showColor() 时,函数中的 this 关键字等于 oCar1。调用 oCar2.showColor() 时,函数中的 this 关键字等于 oCar2。

- -

注意,引用对象的属性时,必须使用 this 关键字。例如,如果采用下面的代码,showColor() 方法不能运行:

- -
-function showColor() {
-  alert(color);
-};
-
- -

如果不用对象或 this 关键字引用变量,ECMAScript 就会把它看作局部变量或全局变量。然后该函数将查找名为 color 的局部或全局变量,但是不会找到。结果如何呢?该函数将在警告中显示 "null"。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/对象应用.html b/app/src/main/assets/help/w3c/对象应用.html deleted file mode 100644 index 186b1e9a..00000000 --- a/app/src/main/assets/help/w3c/对象应用.html +++ /dev/null @@ -1,80 +0,0 @@ -
- -

ECMAScript 对象应用

- -
- -
- - -
-

对象的创建和销毁都在 JavaScript 执行过程中发生,理解这种范式的含义对理解整个语言至关重要。

-
- - -
-

声明和实例化

- -

对象的创建方式是用关键字 new 后面跟上实例化的类的名字:

- -
-var oObject = new Object();
-var oStringObject = new String();
-
- -

第一行代码创建了 Object 类的一个实例,并把它存储到变量 oObject 中。第二行代码创建了 String 类的一个实例,把它存储在变量 oStringObject 中。如果构造函数无参数,括号则不是必需的。因此可以采用下面的形式重写上面的两行代码:

- -
-var oObject = new Object;
-var oStringObject = new String;
-
-
- - -
-

对象引用

- -

在前面的章节中,我们介绍了引用类型的概念。在 ECMAScript 中,不能访问对象的物理表示,只能访问对象的引用。每次创建对象,存储在变量中的都是该对象的引用,而不是对象本身。

-
- - -
-

对象废除

- -

ECMAScript 拥有无用存储单元收集程序(garbage collection routine),意味着不必专门销毁对象来释放内存。当再没有对对象的引用时,称该对象被废除(dereference)了。运行无用存储单元收集程序时,所有废除的对象都被销毁。每当函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其他不可预知的情况下,无用存储单元收集程序也会运行。

- -

把对象的所有引用都设置为 null,可以强制性地废除对象。例如:

- -
-var oObject = new Object;
-// do something with the object here
-oObject = null;
-
- -

当变量 oObject 设置为 null 后,对第一个创建的对象的引用就不存在了。这意味着下次运行无用存储单元收集程序时,该对象将被销毁。

- -

每用完一个对象后,就将其废除,来释放内存,这是个好习惯。这样还确保不再使用已经不能访问的对象,从而防止程序设计错误的出现。此外,旧的浏览器(如 IE/MAC)没有全面的无用存储单元收集程序,所以在卸载页面时,对象可能不能被正确销毁。废除对象和它的所有特性是确保内存使用正确的最好方法。

- -

注意:废除对象的所有引用时要当心。如果一个对象有两个或更多引用,则要正确废除该对象,必须将其所有引用都设置为 null。

-
- - -
-

早绑定和晚绑定

- -

所谓绑定(binding),即把对象的接口与对象实例结合在一起的方法。

- -

早绑定(early binding)是指在实例化对象之前定义它的属性和方法,这样编译器或解释程序就能够提前转换机器代码。在 Java 和 Visual Basic 这样的语言中,有了早绑定,就可以在开发环境中使用 IntelliSense(即给开发者提供对象中属性和方法列表的功能)。ECMAScript 不是强类型语言,所以不支持早绑定。

- -

另一方面,晚绑定(late binding)指的是编译器或解释程序在运行前,不知道对象的类型。使用晚绑定,无需检查对象的类型,只需检查对象是否支持属性和方法即可。ECMAScript 中的所有变量都采用晚绑定方法。这样就允许执行大量的对象操作,而无任何惩罚。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/对象类型.html b/app/src/main/assets/help/w3c/对象类型.html deleted file mode 100644 index c15e33e7..00000000 --- a/app/src/main/assets/help/w3c/对象类型.html +++ /dev/null @@ -1,86 +0,0 @@ -
- -

ECMAScript 对象类型

- -
- -
- - -
-

在 ECMAScript 中,所有对象并非同等创建的。

-

一般来说,可以创建并使用的对象有三种:本地对象、内置对象和宿主对象。

-
- - -
-

本地对象

- -

ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:

- -
    -
  • Object
  • -
  • Function
  • -
  • Array
  • -
  • String
  • -
  • Boolean
  • -
  • Number
  • -
  • Date
  • -
  • RegExp
  • -
  • Error
  • -
  • EvalError
  • -
  • RangeError
  • -
  • ReferenceError
  • -
  • SyntaxError
  • -
  • TypeError
  • -
  • URIError
  • -
- -

相关页面

- -

JavaScript 高级教程:ECMAScript 引用类型

-

JavaScript 高级教程:ECMAScript Function 类

-

JavaScript 参考手册:Array 对象

-

JavaScript 参考手册:Boolean 对象

-

JavaScript 参考手册:Date 对象

-

JavaScript 参考手册:Number 对象

-

JavaScript 参考手册:String 对象

-

JavaScript 参考手册:RegExp 对象

-
- - -
-

内置对象

- -

ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。

- -

相关页面

- -

JavaScript 参考手册:Global 对象

-

JavaScript 参考手册:Math 对象

-
- - -
-

宿主对象

- -

所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。

- -

所有 BOM 和 DOM 对象都是宿主对象。

- -

相关页面

- -

JavaScript 高级教程:JavaScript 实现

-

W3School 参考手册:JavaScript 参考手册

-

W3School 教程:HTML DOM 教程

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/引用类型.html b/app/src/main/assets/help/w3c/引用类型.html deleted file mode 100644 index 63e09045..00000000 --- a/app/src/main/assets/help/w3c/引用类型.html +++ /dev/null @@ -1,418 +0,0 @@ -
- -

ECMAScript 引用类型

- -
- -
- - -
-

引用类型通常叫做类(class)。

-

本教程会讨论大量的 ECMAScript 预定义引用类型。

-
- - -
-

引用类型

- -

引用类型通常叫做类(class),也就是说,遇到引用值,所处理的就是对象。

- -

本教程会讨论大量的 ECMAScript 预定义引用类型。

- -

从现在起,将重点讨论与已经讨论过的原始类型紧密相关的引用类型。

- -

注意:从传统意义上来说,ECMAScript 并不真正具有类。事实上,除了说明不存在类,在 ECMA-262 中根本没有出现“类”这个词。ECMAScript 定义了“对象定义”,逻辑上等价于其他程序设计语言中的类。

- -

提示:本教程将使用术语“对象”。

- -

对象是由 new 运算符加上要实例化的对象的名字创建的。例如,下面的代码创建 Object 对象的实例:

- -
var o = new Object();
- -

这种语法与 Java 语言的相似,不过当有不止一个参数时,ECMAScript 要求使用括号。如果没有参数,如以下代码所示,括号可以省略:

- -
var o = new Object;
- -

注意:尽管括号不是必需的,但是为了避免混乱,最好使用括号。

- -

提示:我们会在对象基础这一章中更深入地探讨对象及其行为。

- -

这一节的重点是具有等价的原始类型的引用类型。

- -
- - -
-

Object 对象

- -

Object 对象自身用处不大,不过在了解其他类之前,还是应该了解它。因为 ECMAScript 中的 Object 对象与 Java 中的 java.lang.Object 相似,ECMAScript 中的所有对象都由这个对象继承而来,Object 对象中的所有属性和方法都会出现在其他对象中,所以理解了 Object 对象,就可以更好地理解其他对象。

- -

Object 对象具有下列属性:

- -
-
constructor
-
对创建对象的函数的引用(指针)。对于 Object 对象,该指针指向原始的 Object() 函数。
- -
Prototype
-
对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例。
-
- - -

Object 对象还具有几个方法:

- -
-
hasOwnProperty(property)
-
判断对象是否有某个特定的属性。必须用字符串指定该属性。(例如,o.hasOwnProperty("name"))
- -
IsPrototypeOf(object)
-
判断该对象是否为另一个对象的原型。
- -
PropertyIsEnumerable
-
判断给定的属性是否可以用 for...in 语句进行枚举。
- -
ToString()
-
返回对象的原始字符串表示。对于 Object 对象,ECMA-262 没有定义这个值,所以不同的 ECMAScript 实现具有不同的值。
- -
ValueOf()
-
返回最适合该对象的原始值。对于许多对象,该方法返回的值都与 ToString() 的返回值相同。
-
- -

注释:上面列出的每种属性和方法都会被其他对象覆盖。

-
- - -
-

Boolean 对象

- -

Boolean 对象是 Boolean 原始类型的引用类型。

- -

要创建 Boolean 对象,只需要传递 Boolean 值作为参数:

- -
var oBooleanObject = new Boolean(true);
- -

Boolean 对象将覆盖 Object 对象的 ValueOf() 方法,返回原始值,即 true 和 false。ToString() 方法也会被覆盖,返回字符串 "true" 或 "false"。

- -

遗憾的是,在 ECMAScript 中很少使用 Boolean 对象,即使使用,也不易理解。

- -

问题通常出现在 Boolean 表达式中使用 Boolean 对象时。例如:

- -
-var oFalseObject = new Boolean(false);
-var bResult = oFalseObject && true;	//输出 true
-
- -

在这段代码中,用 false 值创建 Boolean 对象。然后用这个值与原始值 true 进行 AND 操作。在 Boolean 运算中,false 和 true 进行 AND 操作的结果是 false。不过,在这行代码中,计算的是 oFalseObject,而不是它的值 false。

- -

正如前面讨论过的,在 Boolean 表达式中,所有对象都会被自动转换为 true,所以 oFalseObject 的值是 true。然后 true 再与 true 进行 AND 操作,结果为 true。

- -

注意:虽然你应该了解 Boolean 对象的可用性,不过最好还是使用 Boolean 原始值,避免发生这一节提到的问题。

- - -

参阅

- -

如需更多有关 Boolean 对象的信息,请访问 JavaScript Boolean 对象参考手册

-
- - -
-

Number 对象

- -

正如你可能想到的,Number 对象是 Number 原始类型的引用类型。要创建 Number 对象,采用下列代码:

- -
var oNumberObject = new Number(68);
- -

您应该已认出本章前面小节中讨论特殊值(如 Number.MAX_VALUE)时提到的 Number 对象。所有特殊值都是 Number 对象的静态属性。

- -

要得到数字对象的 Number 原始值,只需要使用 valueOf() 方法:

- -
var iNumber = oNumberObject.valueOf();
- -

当然,Number 类也有 toString() 方法,在讨论类型转换的小节中已经详细讨论过该方法。

- -

除了从 Object 对象继承的标准方法外,Number 对象还有几个处理数值的专用方法。

- -

toFixed() 方法

- -

toFixed() 方法返回的是具有指定位数小数的数字的字符串表示。例如:

- -
-var oNumberObject = new Number(68);
-alert(oNumberObject.toFixed(2));  //输出 "68.00"
-
- -

在这里,toFixed() 方法的参数是 2,说明应该显示两位小数。该方法返回 "68.00",空的字符串位由 0 来补充。对于处理货币的应用程序,该方法非常有用。toFixed() 方法能表示具有 0 到 20 位小数的数字,超过这个范围的值会引发错误。

- -

toExponential() 方法

- -

与格式化数字相关的另一个方法是 toExponential(),它返回的是用科学计数法表示的数字的字符串形式。

- -

与 toFixed() 方法相似,toExponential() 方法也有一个参数,指定要输出的小数的位数。例如:

- -
-var oNumberObject = new Number(68);
-alert(oNumberObject.toExponential(1));  //输出 "6.8e+1"
-
- -

这段代码的结果是 "6.8e+1",前面解释过,它表示 6.8x101。问题是,如果不知道要用哪种形式(预定形式或指数形式)表示数字怎么办?可以用 toPrecision() 方法。

- -

toPrecision() 方法

- -

toPrecision() 方法根据最有意义的形式来返回数字的预定形式或指数形式。它有一个参数,即用于表示数的数字总数(不包括指数)。例如,

- -
-var oNumberObject = new Number(68);
-alert(oNumberObject.toPrecision(1));  //输出 "7e+1"
-
- -

这段代码的任务是用一位数字表示数字 68,结果为 "7e+1",以另外的形式表示即 70。的确,toPrecision() 方法会对数进行舍入。不过,如果用 2 位数字表示 68,就容易多了:

- -
-var oNumberObject = new Number(68);
-alert(oNumberObject.toPrecision(2));  //输出 "68"
-
- -

当然,输出的是 "68",因为这正是该数的准确表示。不过,如果指定的位数多于需要的位数又如何呢?

- -
-var oNumberObject = new Number(68);
-alert(oNumberObject.toPrecision(3));  //输出 "68.0"
-
- -

在这种情况下,toPrecision(3) 等价于 toFixed(1),输出的是 "68.0"。 - -

toFixed()、toExponential() 和 toPrecision() 方法都会进行舍入操作,以便用正确的小数位数正确地表示一个数。 - -

提示:与 Boolean 对象相似,Number 对象也很重要,不过应该少用这种对象,以避免潜在的问题。只要可能,都使用数字的原始表示法。

- - -

参阅

- -

如需更多有关 Number 对象的信息,请访问 JavaScript Number 对象参考手册

-
- - -
-

String 对象

- -

String 对象是 String 原始类型的对象表示法,它是以下方式创建的:

- -
var oStringObject = new String("hello world");
- -

String 对象的 valueOf() 方法和 toString() 方法都会返回 String 类型的原始值:

- -
alert(oStringObject.valueOf() == oStringObject.toString());	//输出 "true"
- -

如果运行这段代码,输出是 "true",说明这些值真的相等。

- -

注释:String 对象是 ECMAScript 中比较复杂的引用类型之一。同样,本节的重点只是 String 类的基本功能。更多的高级功能请阅读本教程相关的章节,或参阅 JavaScript String 对象参考手册

- - -

length 属性

- -

String 对象具有属性 length,它是字符串中的字符个数:

- -
-var oStringObject = new String("hello world");
-alert(oStringObject.length);	//输出 "11"
-
- -

这个例子输出的是 "11",即 "hello world" 中的字符个数。注意,即使字符串包含双字节的字符(与 ASCII 字符相对,ASCII 字符只占用一个字节),每个字符也只算一个字符。

- - -

charAt() 和 charCodeAt() 方法

- -

String 对象还拥有大量的方法。

- -

首先,两个方法 charAt() 和 charCodeAt() 访问的是字符串中的单个字符。这两个方法都有一个参数,即要操作的字符的位置。

- -

charAt() 方法返回的是包含指定位置处的字符的字符串:

- -
-var oStringObject = new String("hello world");
-alert(oStringObject.charAt(1));	//输出 "e"
-
- -

在字符串 "hello world" 中,位置 1 处的字符是 "e"。在“ECMAScript 原始类型”这一节中我们讲过,第一个字符的位置是 0,第二个字符的位置是 1,依此类推。因此,调用 charAt(1) 返回的是 "e"。

- -

如果想得到的不是字符,而是字符代码,那么可以调用 charCodeAt() 方法:

- -
-var oStringObject = new String("hello world");
-alert(oStringObject.charCodeAt(1));	//输出 "101"
-
- -

这个例子输出 "101",即小写字母 "e" 的字符代码。

- - -

concat() 方法

- -

接下来是 concat() 方法,用于把一个或多个字符串连接到 String 对象的原始值上。该方法返回的是 String 原始值,保持原始的 String 对象不变:

- -
-var oStringObject = new String("hello ");
-var sResult = oStringObject.concat("world");
-alert(sResult);		//输出 "hello world"
-alert(oStringObject);	//输出 "hello "
-
- -

在上面这段代码中,调用 concat() 方法返回的是 "hello world",而 String 对象存放的仍然是 "hello "。出于这种原因,较常见的是用加号(+)连接字符串,因为这种形式从逻辑上表明了真正的行为:

- -
-var oStringObject = new String("hello ");
-var sResult = oStringObject + "world";
-alert(sResult);		//输出 "hello world"
-alert(oStringObject);	//输出 "hello "
-
- - -

indexOf() 和 lastIndexOf() 方法

- -

迄今为止,已讨论过连接字符串的方法,访问字符串中的单个字符的方法。不过如果无法确定在某个字符串中是否确实存在一个字符,应该调用什么方法呢?这时,可调用 indexOf() 和 lastIndexOf() 方法。

- -

indexOf() 和 lastIndexOf() 方法返回的都是指定的子串在另一个字符串中的位置,如果没有找不到子串,则返回 -1。

- -

这两个方法的不同之处在于,indexOf() 方法是从字符串的开头(位置 0)开始检索字符串,而 lastIndexOf() 方法则是从字符串的结尾开始检索子串。例如:

- -
-var oStringObject = new String("hello world!");
-alert(oStringObject.indexOf("o"));		输出 "4"
-alert(oStringObject.lastIndexOf("o"));	输出 "7"
-
- -

在这里,第一个 "o" 字符串出现在位置 4,即 "hello" 中的 "o";最后一个 "o" 出现在位置 7,即 "world" 中的 "o"。如果该字符串中只有一个 "o" 字符串,那么 indexOf() 和 lastIndexOf() 方法返回的位置相同。

- - -

localeCompare() 方法

- -

下一个方法是 localeCompare(),对字符串进行排序。该方法有一个参数 - 要进行比较的字符串,返回的是下列三个值之一:

- -
    -
  • 如果 String 对象按照字母顺序排在参数中的字符串之前,返回负数。
  • -
  • 如果 String 对象等于参数中的字符串,返回 0
  • -
  • 如果 String 对象按照字母顺序排在参数中的字符串之后,返回正数。
  • -
- -

注释:如果返回负数,那么最常见的是 -1,不过真正返回的是由实现决定的。如果返回正数,那么同样的,最常见的是 1,不过真正返回的是由实现决定的。

- -

示例如下:

- -
-var oStringObject = new String("yellow");
-alert(oStringObject.localeCompare("brick"));		//输出 "1"
-alert(oStringObject.localeCompare("yellow"));		//输出 "0"
-alert(oStringObject.localeCompare("zoo"));		//输出 "-1"
-
- -

在这段代码中,字符串 "yellow" 与 3 个值进行了对比,即 "brick"、"yellow" 和 "zoo"。由于按照字母顺序排列,"yellow" 位于 "brick" 之后,所以 localeCompare() 返回 1;"yellow" 等于 "yellow",所以 localeCompare() 返回 0;"zoo" 位于 "yellow" 之后,localeCompare() 返回 -1。再强调一次,由于返回的值是由实现决定的,所以最好以下面的方式调用 localeCompare() 方法:

- -
-var oStringObject1 = new String("yellow");
-var oStringObject2 = new String("brick");
-
-var iResult = oStringObject1.localeCompare(oStringObject2);
-
-if(iResult < 0) {
-  alert(oStringObject1 + " comes before " + oStringObject2);
-} else if (iResult > 0) {
-  alert(oStringObject1 + " comes after " + oStringObject2);
-} else {
-  alert("The two strings are equal");
-}
-
- -

采用这种结构,可以确保这段代码在所有实现中都能正确运行。

- -

localeCompare() 方法的独特之处在于,实现所处的区域(locale,兼指国家/地区和语言)确切说明了这种方法运行的方式。在美国,英语是 ECMAScript 实现的标准语言,localeCompare() 是区分大小写的,大写字母在字母顺序上排在小写字母之后。不过,在其他区域,情况可能并非如此。

- - -

slice() 和 substring()

- -

ECMAScript 提供了两种方法从子串创建字符串值,即 slice() 和 substring()。这两种方法返回的都是要处理的字符串的子串,都接受一个或两个参数。第一个参数是要获取的子串的起始位置,第二个参数(如果使用的话)是要获取子串终止前的位置(也就是说,获取终止位置处的字符不包括在返回的值内)。如果省略第二个参数,终止位就默认为字符串的长度。

- -

与 concat() 方法一样,slice() 和 substring() 方法都不改变 String 对象自身的值。它们只返回原始的 String 值,保持 String 对象不变。

- -
-var oStringObject = new String("hello world");
-alert(oStringObject.slice("3"));		//输出 "lo world"
-alert(oStringObject.substring("3"));		//输出 "lo world"
-alert(oStringObject.slice("3", "7"));		//输出 "lo w"
-alert(oStringObject.substring("3", "7"));	//输出 "lo w"
-
- -

在这个例子中,slice() 和 substring() 的用法相同,返回值也一样。当只有参数 3 时,两个方法返回的都是 "lo world",因为 "hello" 中的第二个 "l" 位于位置 3 上。当有两个参数 "3" 和 "7" 时,两个方法返回的值都是 "lo w"("world" 中的字母 "o" 位于位置 7 上,所以它不包括在结果中)。

- -

为什么有两个功能完全相同的方法呢?事实上,这两个方法并不完全相同,不过只在参数为负数时,它们处理参数的方式才稍有不同。

- -

对于负数参数,slice() 方法会用字符串的长度加上参数,substring() 方法则将其作为 0 处理(也就是说将忽略它)。例如:

- -
-var oStringObject = new String("hello world");
-alert(oStringObject.slice("-3"));		//输出 "rld"
-alert(oStringObject.substring("-3"));	//输出 "hello world"
-alert(oStringObject.slice("3, -4"));		//输出 "lo w"
-alert(oStringObject.substring("3, -4"));	//输出 "hel"
-
- -

这样即可看出 slice() 和 substring() 方法的主要不同。

- -

当只有参数 -3 时,slice() 返回 "rld",substring() 则返回 "hello world"。这是因为对于字符串 "hello world",slice("-3") 将被转换成 slice("8"),而 substring("-3") 将被转换成 substring("0")。

- -

同样,使用参数 3 和 -4 时,差别也很明显。slice() 将被转换成 slice(3, 7),与前面的例子相同,返回 "lo w"。而 substring() 方法则将两个参数解释为 substring(3, 0),实际上即 substring(0, 3),因为 substring() 总把较小的数字作为起始位,较大的数字作为终止位。因此,substring("3, -4") 返回的是 "hel"。这里的最后一行代码用来说明如何使用这些方法。

- - -

toLowerCase()、toLocaleLowerCase()、toUpperCase() 和 toLocaleUpperCase()

- -

最后一套要讨论的方法涉及大小写转换。有 4 种方法用于执行大小写转换,即

- -
    -
  • toLowerCase()
  • -
  • toLocaleLowerCase()
  • -
  • toUpperCase()
  • -
  • toLocaleUpperCase()
  • -
- -

从名字上可以看出它们的用途,前两种方法用于把字符串转换成全小写的,后两种方法用于把字符串转换成全大写的。

- -

toLowerCase() 和 toUpperCase() 方法是原始的,是以 java.lang.String 中相同方法为原型实现的。

- -

toLocaleLowerCase() 和 toLocaleUpperCase() 方法是基于特定的区域实现的(与 localeCompare() 方法相同)。在许多区域中,区域特定的方法都与通用的方法完全相同。不过,有几种语言对 Unicode 大小写转换应用了特定的规则(例如土耳其语),因此必须使用区域特定的方法才能进行正确的转换。

- -
-var oStringObject = new String("Hello World");
-alert(oStringObject.toLocaleUpperCase());	//输出 "HELLO WORLD"
-alert(oStringObject.toUpperCase());		//输出 "HELLO WORLD"
-alert(oStringObject.toLocaleLowerCase());	//输出 "hello world"
-alert(oStringObject.toLowerCase());		//输出 "hello world"
-
- -

这段代码中,toUpperCase() 和 toLocaleUpperCase() 输出的都是 "HELLO WORLD",toLowerCase() 和 toLocaleLowerCase() 输出的都是 "hello world"。一般来说,如果不知道在以哪种编码运行一种语言,则使用区域特定的方法比较安全。

- -

提示:记住,String 对象的所有属性和方法都可应用于 String 原始值上,因为它们是伪对象。

-
- - -
-

instanceof 运算符

- -

在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object"。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。

- -

instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:

- -
-var oStringObject = new String("hello world");
-alert(oStringObject instanceof String);	//输出 "true"
-
- -

这段代码问的是“变量 oStringObject 是否为 String 对象的实例?”oStringObject 的确是 String 对象的实例,因此结果是 "true"。尽管不像 typeof 方法那样灵活,但是在 typeof 方法返回 "object" 的情况下,instanceof 方法还是很有用的。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/条件运算符.html b/app/src/main/assets/help/w3c/条件运算符.html deleted file mode 100644 index 0d0e57d5..00000000 --- a/app/src/main/assets/help/w3c/条件运算符.html +++ /dev/null @@ -1,34 +0,0 @@ -
- -

ECMAScript 条件运算符

- -
- -
- - -
-

条件运算符

- -

条件运算符是 ECMAScript 中功能最多的运算符,它的形式与 Java 中的相同。

- -
variable = boolean_expression ? true_value : false_value;
- -

该表达式主要是根据 boolean_expression 的计算结果有条件地为变量赋值。如果 Boolean_expression 为 true,就把 true_value 赋给变量;如果它是 false,就把 false_value 赋给变量。

- -

例如:

- -
var iMax = (iNum1 > iNum2) ? iNum1 : iNum2;
- -

在这里例子中,iMax 将被赋予数字中的最大值。表达式声明如果 iNum1 大于 iNum2,则把 iNum1 赋予 iMax。但如果表达式为 false(即 iNum2 大于或等于 iNum1),则把 iNum2 赋予 iMax。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/标签语句.html b/app/src/main/assets/help/w3c/标签语句.html deleted file mode 100644 index c1c439ad..00000000 --- a/app/src/main/assets/help/w3c/标签语句.html +++ /dev/null @@ -1,34 +0,0 @@ -
- -

ECMAScript 标签语句

- -
- -
- - -
-

有标签的语句

- -

可以用下列语句给语句加标签,以便以后调用:

- -
label : statement
- -

例如:

- -
start : i = 5;
- -

在这个例子中,标签 start 可以被之后的 break 或 continue 语句引用。

- -

提示:在下面的章节,我们将为您介绍 break 和 continue 语句。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/等性运算符.html b/app/src/main/assets/help/w3c/等性运算符.html deleted file mode 100644 index 91f135ff..00000000 --- a/app/src/main/assets/help/w3c/等性运算符.html +++ /dev/null @@ -1,145 +0,0 @@ -
- -

ECMAScript 等性运算符

- -
- -
- -
-

判断两个变量是否相等是程序设计中非常重要的运算。在处理原始值时,这种运算相当简单,但涉及对象,任务就稍有点复杂。

-

ECMAScript 提供了两套等性运算符:等号和非等号用于处理原始值,全等号和非全等号用于处理对象。

-
- -
-

等号和非等号

- -

在 ECMAScript 中,等号由双等号(==)表示,当且仅当两个运算数相等时,它返回 true。非等号由感叹号加等号(!=)表示,当且仅当两个运算数不相等时,它返回 true。为确定两个运算数是否相等,这两个运算符都会进行类型转换。

- -

执行类型转换的规则如下:

- -
    -
  • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
  • -
  • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
  • -
  • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
  • -
  • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。
  • -
- -

在比较时,该运算符还遵守下列规则:

- -
    -
  • 值 null 和 undefined 相等。
  • -
  • 在检查相等性时,不能把 null 和 undefined 转换成其他值。
  • -
  • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。
  • -
  • 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。
  • -
- -

重要提示:即使两个数都是 NaN,等号仍然返回 false,因为根据规则,NaN 不等于 NaN。

- -

下表列出了一些特殊情况,以及它们的结果:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
表达式
null == undefinedtrue
"NaN" == NaNfalse
5 == NaNfalse
NaN == NaNfalse
NaN != NaNtrue
false == 0true
true == 1true
true == 2false
undefined == 0false
null == 0false
"5" == 5true
-
- - -
-

全等号和非全等号

- -

等号和非等号的同类运算符是全等号和非全等号。这两个运算符所做的与等号和非等号相同,只是它们在检查相等性前,不执行类型转换。

- -

全等号由三个等号表示(===),只有在无需类型转换运算数就相等的情况下,才返回 true。

- -

例如:

- -
-var sNum = "66";
-var iNum = 66;
-alert(sNum == iNum);	//输出 "true"
-alert(sNum === iNum);	//输出 "false"
-
- -

在这段代码中,第一个 alert 使用等号来比较字符串 "66" 和数字 66,输出 "true"。如前所述,这是因为字符串 "66" 将被转换成数字 66,,然后才与另一个数字 66 进行比较。第二个 alert 使用全等号在没有类型转换的情况下比较字符串和数字,当然,字符串不等于数字,所以输出 "false"。

- -

非全等号由感叹号加两个等号(!==)表示,只有在无需类型转换运算数不相等的情况下,才返回 true。

- -

例如:

- -
-var sNum = "66";
-var iNum = 66;
-alert(sNum != iNum);	//输出 "false"
-alert(sNum !== iNum);	//输出 "true"
-
- -

这里,第一个 alert 使用非等号,把字符串 "66" 转换成数字 66,使得它与第二个运算数 66 相等。因此,计算结果为 "false",因为两个运算数是相等的。第二个 alert 使用的非全等号。该运算是在问:"sNum" 与 "iNum" 不同吗?这个问题的答案是:是的(true),因为 sNum 是字符串,而 iNum 是数字,它们当然不同。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/类型转换.html b/app/src/main/assets/help/w3c/类型转换.html deleted file mode 100644 index fb8347f7a..00000000 --- a/app/src/main/assets/help/w3c/类型转换.html +++ /dev/null @@ -1,282 +0,0 @@ -
- -

ECMAScript 类型转换

- - -
- -
- - -
-

所有程序设计语言最重要的特征之一是具有进行类型转换的能力。

-

ECMAScript 给开发者提供了大量简单的类型转换方法。

-

大部分类型具有进行简单转换的方法,还有几个全局方法可以用于更复杂的转换。无论哪种情况,在 ECMAScript 中,类型转换都是简短的一步操作。

-
- - -
-

转换成字符串

- -

ECMAScript 的 Boolean 值、数字和字符串的原始值的有趣之处在于它们是伪对象,这意味着它们实际上具有属性和方法。

- -

例如,要获得字符串的长度,可以采用下面的代码:

- -
-var sColor = "red";
-alert(sColor.length);	//输出 "3"
-
- -

尽管 "red" 是原始类型的字符串,它仍然具有属性 length,用于存放字符串的大小。

- -

总而言之,3 种主要的原始类型 Boolean 值、数字和字符串都有 toString() 方法,可以把它们的值转换成字符串。

- -

提示:您也许会问,“字符串还有 toString() 方法吗,这不是多余吗?”是的,的确如此,不过 ECMAScript 定义所有对象都有 toString() 方法,无论它是伪对象,还是真对象。因为 String 类型属于伪对象,所以它一定有 toString() 方法。

- -

Boolean 类型的 toString() 方法只是输出 "true" 或 "false",结果由变量的值决定:

- -
-var bFound = false;
-alert(bFound.toString());	//输出 "false"
-
- -

Number 类型的 toString() 方法比较特殊,它有两种模式,即默认模式基模式。采用默认模式,toString() 方法只是用相应的字符串输出数字值(无论是整数、浮点数还是科学计数法),如下所示:

- -
-var iNum1 = 10;
-var iNum2 = 10.0;
-alert(iNum1.toString());	//输出 "10"
-alert(iNum2.toString());	//输出 "10"
-
- -

注释:在默认模式中,无论最初采用什么表示法声明数字,Number 类型的 toString() 方法返回的都是数字的十进制表示。因此,以八进制或十六进制字面量形式声明的数字输出的都是十进制形式的。

- -

采用 Number 类型的 toString() 方法的基模式,可以用不同的输出数字,例如二进制的基是 2,八进制的基是 8,十六进制的基是 16。

- -

只是要转换成的基数的另一种加法而已,它是 toString() 方法的参数:

- -
-var iNum = 10;
-alert(iNum.toString(2));	//输出 "1010"
-alert(iNum.toString(8));	//输出 "12"
-alert(iNum.toString(16));	//输出 "A"
-
- -

在前面的示例中,以 3 种不同的形式输出了数字 10,即二进制形式、八进制形式和十六进制形式。HTML 采用十六进制表示每种颜色,在 HTML 中处理数字时这种功能非常有用。

- -

注释:对数字调用 toString(10) 与调用 toString() 相同,它们返回的都是该数字的十进制形式。

- -

参阅:

-

请参阅 JavaScript 参考手册提供的有关 toString() 方法的详细信息:

- -
- - -
-

转换成数字

- -

ECMAScript 提供了两种把非数字的原始值转换成数字的方法,即 parseInt() 和 parseFloat()。

- -

正如您可能想到的,前者把值转换成整数,后者把值转换成浮点数。只有对 String 类型调用这些方法,它们才能正确运行;对其他类型返回的都是 NaN。

- -

parseInt()

- -

在判断字符串是否是数字值前,parseInt() 和 parseFloat() 都会仔细分析该字符串。

- -

parseInt() 方法首先查看位置 0 处的字符,判断它是否是个有效数字;如果不是,该方法将返回 NaN,不再继续执行其他操作。但如果该字符是有效数字,该方法将查看位置 1 处的字符,进行同样的测试。这一过程将持续到发现非有效数字的字符为止,此时 parseInt() 将把该字符之前的字符串转换成数字。

- -

例如,如果要把字符串 "12345red" 转换成整数,那么 parseInt() 将返回 12345,因为当它检查到字符 r 时,就会停止检测过程。

- -

字符串中包含的数字字面量会被正确转换为数字,比如 "0xA" 会被正确转换为数字 10。不过,字符串 "22.5" 将被转换成 22,因为对于整数来说,小数点是无效字符。

- -

一些示例如下:

- -
-var iNum1 = parseInt("12345red");	//返回 12345
-var iNum1 = parseInt("0xA");	//返回 10
-var iNum1 = parseInt("56.9");	//返回 56
-var iNum1 = parseInt("red");	//返回 NaN
-
- -

parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。基是由 parseInt() 方法的第二个参数指定的,所以要解析十六进制的值,需如下调用 parseInt() 方法:

- -
var iNum1 = parseInt("AF", 16);	//返回 175
- -

当然,对二进制、八进制甚至十进制(默认模式),都可以这样调用 parseInt() 方法:

- -
-var iNum1 = parseInt("10", 2);	//返回 2
-var iNum2 = parseInt("10", 8);	//返回 8
-var iNum3 = parseInt("10", 10);	//返回 10
-
- -

如果十进制数包含前导 0,那么最好采用基数 10,这样才不会意外地得到八进制的值。例如:

- -
-var iNum1 = parseInt("010");	//返回 8
-var iNum2 = parseInt("010", 8);	//返回 8
-var iNum3 = parseInt("010", 10);	//返回 10
-
- -

在这段代码中,两行代码都把字符 "010" 解析成一个数字。第一行代码把这个字符串看作八进制的值,解析它的方式与第二行代码(声明基数为 8)相同。最后一行代码声明基数为 10,所以 iNum3 最后等于 10。

- -

参阅

- -

请参阅 JavaScript 参考手册提供的有关 parseInt() 方法的详细信息:parseInt()

- - -

parseFloat()

- -

parseFloat() 方法与 parseInt() 方法的处理方式相似,从位置 0 开始查看每个字符,直到找到第一个非有效的字符为止,然后把该字符之前的字符串转换成整数。

- -

不过,对于这个方法来说,第一个出现的小数点是有效字符。如果有两个小数点,第二个小数点将被看作无效的。parseFloat() 会把这个小数点之前的字符转换成数字。这意味着字符串 "11.22.33" 将被解析成 11.22。

- -

使用 parseFloat() 方法的另一不同之处在于,字符串必须以十进制形式表示浮点数,而不是用八进制或十六进制。该方法会忽略前导 0,所以八进制数 0102 将被解析为 102。对于十六进制数 0xA,该方法将返回 NaN,因为在浮点数中,x 不是有效字符。(注释:经测试,具体的浏览器实现会返回 0,而不是 NaN。)

- -

此外,parseFloat() 方法也没有基模式。

- -

下面是使用 parseFloat() 方法的一些示例:

- -
-var fNum1 = parseFloat("12345red");	//返回 12345
-var fNum2 = parseFloat("0xA");	//返回 NaN
-var fNum3 = parseFloat("11.2");	//返回 11.2
-var fNum4 = parseFloat("11.22.33");	//返回 11.22
-var fNum5 = parseFloat("0102");	//返回 102
-var fNum1 = parseFloat("red");	//返回 NaN
-
- -

亲自试一试

- -

参阅

- -

请参阅 JavaScript 参考手册提供的有关 parseFloat() 方法的详细信息:parseFloat()

-
- - -
-

强制类型转换

- -

您还可以使用强制类型转换(type casting)来处理转换值的类型。使用强制类型转换可以访问特定的值,即使它是另一种类型的。

- -

编者注:cast 有“铸造”之意,很贴合“强制转换”的意思。

- -

ECMAScript 中可用的 3 种强制类型转换如下:

- -
    -
  • Boolean(value) - 把给定的值转换成 Boolean 型;
  • -
  • Number(value) - 把给定的值转换成数字(可以是整数或浮点数);
  • -
  • String(value) - 把给定的值转换成字符串;
  • -
- -

用这三个函数之一转换值,将创建一个新值,存放由原始值直接转换成的值。这会造成意想不到的后果。

- -

Boolean() 函数

- -

当要转换的值是至少有一个字符的字符串、非 0 数字或对象时,Boolean() 函数将返回 true。如果该值是空字符串、数字 0、undefined 或 null,它将返回 false。

- -

可以用下面的代码测试 Boolean 型的强制类型转换:

- -
-var b1 = Boolean("");		//false - 空字符串
-var b2 = Boolean("hello");		//true - 非空字符串
-var b1 = Boolean(50);		//true - 非零数字
-var b1 = Boolean(null);		//false - null
-var b1 = Boolean(0);		//false - 零
-var b1 = Boolean(new object());	//true - 对象
-
- -

Number() 函数

- -

Number() 函数的强制类型转换与 parseInt() 和 parseFloat() 方法的处理方式相似,只是它转换的是整个值,而不是部分值。

- -

还记得吗,parseInt() 和 parseFloat() 方法只转换第一个无效字符之前的字符串,因此 "1.2.3" 将分别被转换为 "1" 和 "1.2"。

- -

用 Number() 进行强制类型转换,"1.2.3" 将返回 NaN,因为整个字符串值不能转换成数字。如果字符串值能被完整地转换,Number() 将判断是调用 parseInt() 方法还是 parseFloat() 方法。

- -

下表说明了对不同的值调用 Number() 方法会发生的情况:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
用法结果
Number(false)0
Number(true)1
Number(undefined)NaN
Number(null)0
Number("1.2")1.2
Number("12")12
Number("1.2.3")NaN
Number(new object())NaN
Number(50)50
- -

String() 函数

- -

最后一种强制类型转换方法 String() 是最简单的,因为它可把任何值转换成字符串。

- -

要执行这种强制类型转换,只需要调用作为参数传递进来的值的 toString() 方法,即把 12 转换成 "12",把 true 转换成 "true",把 false 转换成 "false",以此类推。

- -

强制转换成字符串和调用 toString() 方法的唯一不同之处在于,对 null 和 undefined 值强制类型转换可以生成字符串而不引发错误:

- -
-var s1 = String(null);	//"null"
-var oNull = null;
-var s2 = oNull.toString();	//会引发错误
-
- -

在处理 ECMAScript 这样的弱类型语言时,强制类型转换非常有用,不过应该确保使用值的正确。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/继承机制实例.html b/app/src/main/assets/help/w3c/继承机制实例.html deleted file mode 100644 index 185f4fb8..00000000 --- a/app/src/main/assets/help/w3c/继承机制实例.html +++ /dev/null @@ -1,34 +0,0 @@ -
- -

ECMAScript 继承机制实例

- -
- -
- -
-

本节使用一个经典的例子解释 ECMAScript 的继承机制。

-
- -
-

继承机制实例

- -

说明继承机制最简单的方式是,利用一个经典的例子 - 几何形状。实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边)。圆是椭圆的一种,它只有一个焦点。三角形、矩形和五边形都是多边形的一种,具有不同数量的边。正方形是矩形的一种,所有的边等长。这就构成了一种完美的继承关系。

- -

在这个例子中,形状(Shape)是椭圆形(Ellipse)和多边形(Polygon)的基类(base class)(所有类都由它继承而来)。椭圆具有一个属性 foci,说明椭圆具有的焦点的个数。圆形(Circle)继承了椭圆形,因此圆形是椭圆形的子类(subclass),椭圆形是圆形的超类(superclass)。同样,三角形(Triangle)、矩形(Rectangle)和五边形(Pentagon)都是多边形的子类,多边形是它们的超类。最后,正方形(Square)继承了矩形。

- -

最好用图来解释这种继承关系,这是 UML(统一建模语言)的用武之地。UML 的主要用途之一是,可视化地表示像继承这样的复杂对象关系。下面的图示是解释 Shape 和它的子类之间关系的 UML 图示:

- -继承机制 UML 图示实例 - -

在 UML 中,每个方框表示一个类,由类名说明。三角形 、矩形和五边形顶部的线段汇集在一起,指向形状,说明这些类都由形状继承而来。同样,从正方形指向矩形的箭头说明了它们之间的继承关系。

- -
- - -
- -
- - -
diff --git a/app/src/main/assets/help/w3c/继承机制实现.html b/app/src/main/assets/help/w3c/继承机制实现.html deleted file mode 100644 index 526f441a..00000000 --- a/app/src/main/assets/help/w3c/继承机制实现.html +++ /dev/null @@ -1,329 +0,0 @@ -
- -

ECMAScript 继承机制实现

- -
- -
- - -
-

继承机制的实现

- -

要用 ECMAScript 实现继承机制,您可以从要继承的基类入手。所有开发者定义的类都可作为基类。出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击。

- -

选定基类后,就可以创建它的子类了。是否使用基类完全由你决定。有时,你可能想创建一个不能直接使用的基类,它只是用于给子类提供通用的函数。在这种情况下,基类被看作抽象类。

- -

尽管 ECMAScript 并没有像其他语言那样严格地定义抽象类,但有时它的确会创建一些不允许使用的类。通常,我们称这种类为抽象类。

- -

创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类的属性和方法。

- -

继承的方式

- -

和其他功能一样,ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。

- -

下面为您介绍几种具体的继承方式。

-
- - -
-

对象冒充

- -

构想原始的 ECMAScript 时,根本没打算设计对象冒充(object masquerading)。它是在开发者开始理解函数的工作方式,尤其是如何在函数环境中使用 this 关键字后才发展出来。

- -

其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB:

- -
-function ClassA(sColor) {
-    this.color = sColor;
-    this.sayColor = function () {
-        alert(this.color);
-    };
-}
-
-function ClassB(sColor) {
-}
-
- -

还记得吗?关键字 this 引用的是构造函数当前创建的对象。不过在这个方法中,this 指向的所属的对象。这个原理是把 ClassA 作为常规函数来建立继承机制,而不是作为构造函数。如下使用构造函数 ClassB 可以实现继承机制:

- -
-function ClassB(sColor) {
-    this.newMethod = ClassA;
-    this.newMethod(sColor);
-    delete this.newMethod;
-}
-
- -

在这段代码中,为 ClassA 赋予了方法 newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是 ClassB 构造函数的参数 sColor。最后一行代码删除了对 ClassA 的引用,这样以后就不能再调用它。

- -

所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法:

- -
-function ClassB(sColor, sName) {
-    this.newMethod = ClassA;
-    this.newMethod(sColor);
-    delete this.newMethod;
-
-    this.name = sName;
-    this.sayName = function () {
-        alert(this.name);
-    };
-}
-
- -

为证明前面的代码有效,可以运行下面的例子:

- -
-var objA = new ClassA("blue");
-var objB = new ClassB("red", "John");
-objA.sayColor();	//输出 "blue"
-objB.sayColor();	//输出 "red"
-objB.sayName();		//输出 "John"
-
- -

对象冒充可以实现多重继承

- -

有趣的是,对象冒充可以支持多重继承。也就是说,一个类可以继承多个超类。用 UML 表示的多重继承机制如下图所示:

- -继承机制 UML 图示实例 - -

例如,如果存在两个类 ClassX 和 ClassY,ClassZ 想继承这两个类,可以使用下面的代码:

- -
-function ClassZ() {
-    this.newMethod = ClassX;
-    this.newMethod();
-    delete this.newMethod;
-
-    this.newMethod = ClassY;
-    this.newMethod();
-    delete this.newMethod;
-}
-
- -

TIY

- -

这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

- -

由于这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()。

-
- - -
-

call() 方法

- -

call() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。例如:

- -
-function sayColor(sPrefix,sSuffix) {
-    alert(sPrefix + this.color + sSuffix);
-};
-
-var obj = new Object();
-obj.color = "blue";
-
-sayColor.call(obj, "The color is ", "a very nice color indeed.");
-
- -

在这个例子中,函数 sayColor() 在对象外定义,即使它不属于任何对象,也可以引用关键字 this。对象 obj 的 color 属性等于 blue。调用 call() 方法时,第一个参数是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个和第三个参数是字符串。它们与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息 "The color is blue, a very nice color indeed." 将被显示出来。

- -

要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值、调用和删除代码替换即可:

- -
-function ClassB(sColor, sName) {
-    //this.newMethod = ClassA;
-    //this.newMethod(color);
-    //delete this.newMethod;
-    ClassA.call(this, sColor);
-
-    this.name = sName;
-    this.sayName = function () {
-        alert(this.name);
-    };
-}
-
- -

TIY

- -

这里,我们需要让 ClassA 中的关键字 this 等于新创建的 ClassB 对象,因此 this 是第一个参数。第二个参数 sColor 对两个类来说都是唯一的参数。

-
- - -
-

apply() 方法

- -

apply() 方法有两个参数,用作 this 的对象和要传递给函数的参数的数组。例如:

- -
-function sayColor(sPrefix,sSuffix) {
-    alert(sPrefix + this.color + sSuffix);
-};
-
-var obj = new Object();
-obj.color = "blue";
-
-sayColor.apply(obj, new Array("The color is ", "a very nice color indeed."));
-
- -

这个例子与前面的例子相同,只是现在调用的是 apply() 方法。调用 apply() 方法时,第一个参数仍是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个参数是由两个字符串构成的数组,与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息仍是 "The color is blue, a very nice color indeed.",将被显示出来。

- -

该方法也用于替换前三行的赋值、调用和删除新方法的代码:

- -
-function ClassB(sColor, sName) {
-    //this.newMethod = ClassA;
-    //this.newMethod(color);
-    //delete this.newMethod;
-    ClassA.apply(this, new Array(sColor));
-
-    this.name = sName;
-    this.sayName = function () {
-        alert(this.name);
-    };
-}
-
- -

同样的,第一个参数仍是 this,第二个参数是只有一个值 color 的数组。可以把 ClassB 的整个 arguments 对象作为第二个参数传递给 apply() 方法:

- -
-function ClassB(sColor, sName) {
-    //this.newMethod = ClassA;
-    //this.newMethod(color);
-    //delete this.newMethod;
-    ClassA.apply(this, arguments);
-
-    this.name = sName;
-    this.sayName = function () {
-        alert(this.name);
-    };
-}
-
- -

TIY

- -

当然,只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象。如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。此外,还可使用 call() 方法。

-
- - -
-

原型链(prototype chaining)

- -

继承这种形式在 ECMAScript 中原本是用于原型链的。上一章介绍了定义类的原型方式。原型链扩展了这种方式,以一种有趣的方式实现继承机制。

- -

在上一章学过,prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。

- -

如果用原型方式重定义前面例子中的类,它们将变为下列形式:

- -
-function ClassA() {
-}
-
-ClassA.prototype.color = "blue";
-ClassA.prototype.sayColor = function () {
-    alert(this.color);
-};
-
-function ClassB() {
-}
-
-ClassB.prototype = new ClassA();
-
- -

原型方式的神奇之处在于突出显示的蓝色代码行。这里,把 ClassB 的 prototype 属性设置成 ClassA 的实例。这很有意思,因为想要 ClassA 的所有属性和方法,但又不想逐个将它们 ClassB 的 prototype 属性。还有比把 ClassA 的实例赋予 prototype 属性更好的方法吗?

- -

注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。

- -

与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 ClassB 类添加 name 属性和 sayName() 方法的代码如下:

- -
-function ClassB() {
-}
-
-ClassB.prototype = new ClassA();
-
-ClassB.prototype.name = "";
-ClassB.prototype.sayName = function () {
-    alert(this.name);
-};
-
- -

可通过运行下面的例子测试这段代码:

- -
-var objA = new ClassA();
-var objB = new ClassB();
-objA.color = "blue";
-objB.color = "red";
-objB.name = "John";
-objA.sayColor();
-objB.sayColor();
-objB.sayName();
-
- -

TIY

- -

此外,在原型链中,instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。例如:

- -
-var objB = new ClassB();
-alert(objB instanceof ClassA);	//输出 "true"
-alert(objB instanceof ClassB);	//输出 "true"
-
- -

在 ECMAScript 的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。

- -

原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。

-
- - -
-

混合方式

- -

这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。

- -

在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:

- -
-function ClassA(sColor) {
-    this.color = sColor;
-}
-
-ClassA.prototype.sayColor = function () {
-    alert(this.color);
-};
-
-function ClassB(sColor, sName) {
-    ClassA.call(this, sColor);
-    this.name = sName;
-}
-
-ClassB.prototype = new ClassA();
-
-ClassB.prototype.sayName = function () {
-    alert(this.name);
-};
-
- -

在此例子中,继承机制由两行突出显示的蓝色代码实现。在第一行突出显示的代码中,在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性。在第二行突出显示的代码中,用原型链继承 ClassA 类的方法。由于这种混合方式使用了原型链,所以 instanceof 运算符仍能正确运行。

- -

下面的例子测试了这段代码:

- -
-var objA = new ClassA("blue");
-var objB = new ClassB("red", "John");
-objA.sayColor();	//输出 "blue"
-objB.sayColor();	//输出 "red"
-objB.sayName();	//输出 "John"
-
- -

TIY

-
- - -
- -
- - -
diff --git a/app/src/main/assets/help/w3c/语法.html b/app/src/main/assets/help/w3c/语法.html deleted file mode 100644 index 2e9f7b60..00000000 --- a/app/src/main/assets/help/w3c/语法.html +++ /dev/null @@ -1,105 +0,0 @@ -
- -

ECMAScript 语法

- -
- -
- -
-

熟悉 Java、C 和 Perl 这些语言的开发者会发现 ECMAScript 的语法很容易掌握,因为它借用了这些语言的语法。

-

Java 和 ECMAScript 有一些关键的语法特性相同,也有一些完全不同。

-
- - -
-

区分大小写

- -

与 Java 一样,变量、函数名、运算符以及其他一切东西都是区分大小写的。

- -

比如:

- -

变量 test 与变量 TEST 是不同的。

-
- - -
-

变量是弱类型的

- -

与 Java 和 C 不同,ECMAScript 中的变量无特定的类型,定义变量时只用 var 运算符,可以将它初始化为任意值。

- -

因此,可以随时改变变量所存数据的类型(尽量避免这样做)。

- -

例子

- -
-var color = "red";
-var num = 25;
-var visible = true;
-
-
- - -
-

每行结尾的分号可有可无

- -

Java、C 和 Perl 都要求每行代码以分号(;)结束才符合语法。

- -

ECMAScript 则允许开发者自行决定是否以分号结束一行代码。如果没有分号,ECMAScript 就把折行代码的结尾看做该语句的结尾(与 Visual Basic 和 VBScript 相似),前提是这样没有破坏代码的语义。

- -

最好的代码编写习惯是总加入分号,因为没有分号,有些浏览器就不能正确运行,不过根据 ECMAScript 标准,下面两行代码都是正确的:

- -
-var test1 = "red"
-var test2 = "blue";
-
-
- - -
-

注释与 Java、C 和 PHP 语言的注释相同

- -

ECMAScript 借用了这些语言的注释语法。

- -

有两种类型的注释:

- -
    -
  • 单行注释以双斜杠开头(//)
  • -
  • 多行注释以单斜杠和星号开头(/*),以星号和单斜杠结尾(*/)
  • -
- -
-//this is a single-line comment
-
-/*this is a multi-
-line comment*/
-
-
- - -
-

括号表示代码块

- -

从 Java 中借鉴的另一个概念是代码块。

- -

代码块表示一系列应该按顺序执行的语句,这些语句被封装在左括号({)和右括号(})之间。

- -

例如:

- -
-if (test1 == "red") {
-    test1 = "blue";
-    alert(test1);
-}
-
-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/赋值运算符.html b/app/src/main/assets/help/w3c/赋值运算符.html deleted file mode 100644 index cc996926..00000000 --- a/app/src/main/assets/help/w3c/赋值运算符.html +++ /dev/null @@ -1,55 +0,0 @@ -
- -

ECMAScript 赋值运算符

- -
- -
- - -
-

赋值运算符

- -

简单的赋值运算符由等号(=)实现,只是把等号右边的值赋予等号左边的变量。

- -

例如:

- -
var iNum = 10;
- -

复合赋值运算是由乘性运算符、加性运算符或位移运算符加等号(=)实现的。这些赋值运算符是下列这些常见情况的缩写形式:

- -
-var iNum = 10;
-iNum = iNum + 10;
-
- -

可以用一个复合赋值运算符改写第二行代码:

- -
-var iNum = 10;
-iNum += 10;
-
- -

每种主要的算术运算以及其他几个运算都有复合赋值运算符:

- -
    -
  • 乘法/赋值(*=)
  • -
  • 除法/赋值(/=)
  • -
  • 取模/赋值(%=)
  • -
  • 加法/赋值(+=)
  • -
  • 减法/赋值(-=)
  • -
  • 左移/赋值(<<=)
  • -
  • 有符号右移/赋值(>>=)
  • -
  • 无符号右移/赋值(>>>=)
  • -
-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/迭代语句.html b/app/src/main/assets/help/w3c/迭代语句.html deleted file mode 100644 index 43ae1586..00000000 --- a/app/src/main/assets/help/w3c/迭代语句.html +++ /dev/null @@ -1,108 +0,0 @@ -
- -

ECMAScript 迭代语句

- -
- -
- -
-

迭代语句又叫循环语句,声明一组要反复执行的命令,直到满足某些条件为止。

-

循环通常用于迭代数组的值(因此而得名),或者执行重复的算术任务。

-

本节为您介绍 ECMAScript 提供的四种迭代语句。

-
- - -
-

do-while 语句

- -

do-while 语句是后测试循环,即退出条件在执行循环内部的代码之后计算。这意味着在计算表达式之前,至少会执行循环主体一次。

- -

它的语法如下:

- -
do {statement} while (expression);
- -

例子:

- -
-var i = 0;
-do {i += 2;} while (i < 10);
-
-
- - -
-

while 语句

- -

while 语句是前测试循环。这意味着退出条件是在执行循环内部的代码之前计算的。因此,循环主体可能根本不被执行。

- -

它的语法如下:

- -
while (expression) statement
- -

例子:

- -
-var i = 0;
-while (i < 10) {
-  i += 2;
-}
-
-
- - -
-

for 语句

- -

for 语句是前测试循环,而且在进入循环之前,能够初始化变量,并定义循环后要执行的代码。

- -

它的语法如下:

- -
for (initialization; expression; post-loop-expression) statement
- -

注意:post-loop-expression 之后不能写分号,否则无法运行。

- -

例子:

- -
-iCount = 6;
-for (var i = 0; i < iCount; i++) {
-  alert(i);
-}
-
- -

这段代码定义了初始值为 0 的变量 i。只有当条件表达式(i < iCount)的值为 true 时,才进入 for 循环,这样循环主体可能不被执行。如果执行了循环主体,那么将执行循环后表达式,并迭代变量 i。

-
- - -
-

for-in 语句

- -

for 语句是严格的迭代语句,用于枚举对象的属性。

- -

它的语法如下:

- -
for (property in expression) statement
- -

例子:

- -
-for (sProp in window) {
-  alert(sProp);
-}
-
- -

这里,for-in 语句用于显示 window 对象的所有属性。

- -

前面讨论过的 PropertyIsEnumerable() 是 ECMAScript 中专门用于说明属性是否可以用 for-in 语句访问的方法。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/逗号运算符.html b/app/src/main/assets/help/w3c/逗号运算符.html deleted file mode 100644 index d439cafa..00000000 --- a/app/src/main/assets/help/w3c/逗号运算符.html +++ /dev/null @@ -1,30 +0,0 @@ -
- -

ECMAScript 逗号运算符

- -
- -
- - -
-

逗号运算符

- -

用逗号运算符可以在一条语句中执行多个运算。

- -

例如:

- -
var iNum1 = 1, iNum = 2, iNum3 = 3;
- -

逗号运算符常用变量声明中。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/逻辑运算符.html b/app/src/main/assets/help/w3c/逻辑运算符.html deleted file mode 100644 index c4900005..00000000 --- a/app/src/main/assets/help/w3c/逻辑运算符.html +++ /dev/null @@ -1,294 +0,0 @@ -
- -

ECMAScript Boolean 运算符

- -
- -
- - -
-

Boolean 运算符非常重要,它使得程序语言得以正常运行。

-

Boolean 运算符有三种:NOT、AND 和 OR。

-
- - -
-

ToBoolean 操作

- -

在学习各种逻辑运算符之前,让我们先了解一下 ECMAScript-262 v5 规范中描述的 ToBoolean 操作。

- -

抽象操作 ToBoolean 将其参数按照下表中的规则转换为逻辑值:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
参数类型结果
Undefinedfalse
Nullfalse
Boolean结果等于输入的参数(不转换)
Number如果参数为 +0, -0 或 NaN,则结果为 false;否则为 true。
String如果参数为空字符串,则结果为 false;否则为 true。
Objecttrue
-
- - -
-

逻辑 NOT 运算符

- -

在 ECMAScript 中,逻辑 NOT 运算符与 C 和 Java 中的逻辑 NOT 运算符相同,都由感叹号(!)表示。

- -

与逻辑 OR 和逻辑 AND 运算符不同的是,逻辑 NOT 运算符返回的一定是 Boolean 值

- -

逻辑 NOT 运算符的行为如下:

- -
    -
  • 如果运算数是对象,返回 false
  • -
  • 如果运算数是数字 0,返回 true
  • -
  • 如果运算数是 0 以外的任何数字,返回 false
  • -
  • 如果运算数是 null,返回 true
  • -
  • 如果运算数是 NaN,返回 true
  • -
  • 如果运算数是 undefined,发生错误
  • -
- -

通常,该运算符用于控制循环:

- -
-var bFound = false;
-var i = 0;
-
-while (!bFound) {
-  if (aValue[i] == vSearchValues) {
-    bFound = true;
-  } else {
-    i++;
-  }
-}
-
- -

在这个例子中,Boolean 变量(bFound)用于记录检索是否成功。找到问题中的数据项时,bFound 将被设置为 true,!bFound 将等于 false,意味着运行将跳出 while 循环。

- -

判断 ECMAScript 变量的 Boolean 值时,也可以使用逻辑 NOT 运算符。这样做需要在一行代码中使用两个 NOT 运算符。无论运算数是什么类型,第一个 NOT 运算符返回 Boolean 值。第二个 NOT 将对该 Boolean 值求负,从而给出变量真正的 Boolean 值。

- -
-var bFalse = false;
-var sRed = "red";
-var iZero = 0;
-var iThreeFourFive = 345;
-var oObject = new Object;
-
-document.write("bFalse 的逻辑值是 " + (!!bFalse));
-document.write("sRed 的逻辑值是 " + (!!sRed));
-document.write("iZero 的逻辑值是 " + (!!iZero));
-document.write("iThreeFourFive 的逻辑值是 " + (!!iThreeFourFive));
-document.write("oObject 的逻辑值是 " + (!!oObject));
-
- -

结果:

- -
-bFalse 的逻辑值是 false
-sRed 的逻辑值是 true
-iZero 的逻辑值是 false
-iThreeFourFive 的逻辑值是 true
-oObject 的逻辑值是 true 
-
-
- - -
-

逻辑 AND 运算符

- -

在 ECMAScript 中,逻辑 AND 运算符用双和号(&&)表示:

- -

例如:

- -
-var bTrue = true;
-var bFalse = false;
-var bResult = bTrue && bFalse;
-
- -

下面的真值表描述了逻辑 AND 运算符的行为:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
运算数 1运算数 2结果
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse
- -

逻辑 AND 运算的运算数可以是任何类型的,不止是 Boolean 值。

- -

如果某个运算数不是原始的 Boolean 型值,逻辑 AND 运算并不一定返回 Boolean 值:

- -
    -
  • 如果一个运算数是对象,另一个是 Boolean 值,返回该对象。
  • -
  • 如果两个运算数都是对象,返回第二个对象。
  • -
  • 如果某个运算数是 null,返回 null。
  • -
  • 如果某个运算数是 NaN,返回 NaN。
  • -
  • 如果某个运算数是 undefined,发生错误。
  • -
- -

与 Java 中的逻辑 AND 运算相似,ECMAScript 中的逻辑 AND 运算也是简便运算,即如果第一个运算数决定了结果,就不再计算第二个运算数。对于逻辑 AND 运算来说,如果第一个运算数是 false,那么无论第二个运算数的值是什么,结果都不可能等于 true。

- -

考虑下面的例子:

- -
-var bTrue = true;
-var bResult = (bTrue && bUnknown);	//发生错误
-alert(bResult);			//这一行不会执行
-
- -

这段代码在进行逻辑 AND 运算时将引发错误,因为变量 bUnknown 是未定义的。变量 bTrue 的值为 true,因为逻辑 AND 运算将继续计算变量 bUnknown。这样做就会引发错误,因为 bUnknown 的值是 undefined,不能用于逻辑 AND 运算。

- -

如果修改这个例子,把第一个数设为 false,那么就不会发生错误:

- -
-var bFalse = false;
-var bResult = (bFalse && bUnknown);
-alert(bResult);			//输出 "false"
-
- -

在这段代码中,脚本将输出逻辑 AND 运算返回的值,即字符串 "false"。即使变量 bUnknown 的值为 undefined,它也不会被计算,因为第一个运算数的值是 false。

- -

提示:在使用逻辑 AND 运算符时,必须记住它的这种简便计算特性。

-
- - -
-

逻辑 OR 运算符

- -

ECMAScript 中的逻辑 OR 运算符与 Java 中的相同,都由双竖线(||)表示:

- -
-var bTrue = true;
-var bFalse = false;
-var bResult = bTrue || bFalse;
-
- -

下面的真值表描述了逻辑 OR 运算符的行为:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
运算数 1运算数 2结果
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse
- -

与逻辑 AND 运算符相似,如果某个运算数不是 Boolean 值,逻辑 OR 运算并不一定返回 Boolean 值:

- -
    -
  • 如果一个运算数是对象,并且该对象左边的运算数值均为 false,则返回该对象。
  • -
  • 如果两个运算数都是对象,返回第一个对象。
  • -
  • 如果最后一个运算数是 null,并且其他运算数值均为 false,则返回 null。
  • -
  • 如果最后一个运算数是 NaN,并且其他运算数值均为 false,则返回 NaN。
  • -
  • 如果某个运算数是 undefined,发生错误。
  • -
- -

与逻辑 AND 运算符一样,逻辑 OR 运算也是简便运算。对于逻辑 OR 运算符来说,如果第一个运算数值为 true,就不再计算第二个运算数。

- -

例如:

- -
-var bTrue = true;
-var bResult = (bTrue || bUnknown);
-alert(bResult);			//输出 "true"
-
- -

与前面的例子相同,变量 bUnknown 是未定义的。不过,由于变量 bTrue 的值为 true,bUnknown 不会被计算,因此输出的是 "true"。

- -

如果把 bTrue 改为 false,将发生错误:

- -
-var bFalse = false;
-var bResult = (bFalse || bUnknown);	//发生错误
-alert(bResult);			//不会执行这一行
-
-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/闭包(closure).html b/app/src/main/assets/help/w3c/闭包(closure).html deleted file mode 100644 index 7253743c..00000000 --- a/app/src/main/assets/help/w3c/闭包(closure).html +++ /dev/null @@ -1,68 +0,0 @@ -
- -

ECMAScript 闭包(closure)

- -
- -
- - -
-

ECMAScript 最易让人误解的一点是,它支持闭包(closure)。

-

闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。

-
- - -
-

简单的闭包实例

- -

在 ECMAScript 中使用全局变量是一个简单的闭包实例。请思考下面这段代码:

- -
-var sMessage = "hello world";
-
-function sayHelloWorld() {
-  alert(sMessage);
-}
-
-sayHelloWorld();
-
- -

在上面这段代码中,脚本被载入内存后,并没有为函数 sayHelloWorld() 计算变量 sMessage 的值。该函数捕获 sMessage 的值只是为了以后的使用,也就是说,解释程序知道在调用该函数时要检查 sMessage 的值。sMessage 将在函数调用 sayHelloWorld() 时(最后一行)被赋值,显示消息 "hello world"。

-
- - -
-

复杂的闭包实例

- -

在一个函数中定义另一个会使闭包变得更加复杂。例如:

- -
-var iBaseNum = 10;
-
-function addNum(iNum1, iNum2) {
-  function doAdd() {
-    return iNum1 + iNum2 + iBaseNum;
-  }
-  return doAdd();
-}
-
- -

这里,函数 addNum() 包括函数 doAdd() (闭包)。内部函数是一个闭包,因为它将获取外部函数的参数 iNum1 和 iNum2 以及全局变量 iBaseNum 的值。 addNum() 的最后一步调用了 doAdd(),把两个参数和全局变量相加,并返回它们的和。

- -

这里要掌握的重要概念是,doAdd() 函数根本不接受参数,它使用的值是从执行环境中获取的。

- -

可以看到,闭包是 ECMAScript 中非常强大多用的一部分,可用于执行复杂的计算。

- -

提示:就像使用任何高级函数一样,使用闭包要小心,因为它们可能会变得非常复杂。

-
- - -
- -
- - - - -
diff --git a/app/src/main/assets/help/w3c/面向对象技术.html b/app/src/main/assets/help/w3c/面向对象技术.html deleted file mode 100644 index 14f899a5..00000000 --- a/app/src/main/assets/help/w3c/面向对象技术.html +++ /dev/null @@ -1,61 +0,0 @@ -
- -

ECMAScript 面向对象技术

- -
- -
- - -
-

面向对象术语

- -

对象

- -

ECMA-262 把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格来说,这意味着对象是无特定顺序的值的数组。

- -

尽管 ECMAScript 如此定义对象,但它更通用的定义是基于代码的名词(人、地点或事物)的表示。

- -

- -

每个对象都由类定义,可以把类看做对象的配方。类不仅要定义对象的接口(interface)(开发者访问的属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码)。编译器和解释程序都根据类的说明构建对象。

- -

实例

- -

程序使用类创建对象时,生成的对象叫作类的实例(instance)。对类生成的对象的个数的唯一限制来自于运行代码的机器的物理内存。每个实例的行为相同,但实例处理一组独立的数据。由类创建对象实例的过程叫做实例化(instantiation)。

- -

在前面的章节我们提到过,ECMAScript 并没有正式的类。相反,ECMA-262 把对象定义描述为对象的配方。这是 ECMAScript 逻辑上的一种折中方案,因为对象定义实际上是对象自身。即使类并不真正存在,我们也把对象定义叫做类,因为大多数开发者对此术语更熟悉,而且从功能上说,两者是等价的。

-
- - -
-

面向对象语言的要求

- -

一种面向对象语言需要向开发者提供四种基本能力:

- -
    -
  1. 封装 - 把相关的信息(无论数据或方法)存储在对象中的能力
  2. -
  3. 聚集 - 把一个对象存储在另一个对象内的能力
  4. -
  5. 继承 - 由另一个类(或多个类)得来类的属性和方法的能力
  6. -
  7. 多态 - 编写能以多种方法运行的函数或方法的能力
  8. -
- -

ECMAScript 支持这些要求,因此可被是看做面向对象的。

-
- - -
-

对象的构成

- -

在 ECMAScript 中,对象由特性(attribute)构成,特性可以是原始值,也可以是引用值。如果特性存放的是函数,它将被看作对象的方法(method),否则该特性被看作对象的属性(property)。

-
- - -
- -
- - - - -
diff --git a/app/src/main/java/com/stardust/scriptdroid/Pref.java b/app/src/main/java/com/stardust/scriptdroid/Pref.java index b2965d6b..db034126 100644 --- a/app/src/main/java/com/stardust/scriptdroid/Pref.java +++ b/app/src/main/java/com/stardust/scriptdroid/Pref.java @@ -144,4 +144,7 @@ public class Pref { return def().getBoolean(getString(R.string.key_stable_mode), false); } + public static String getDocumentationUrl() { + return "file:///android_asset/docs/"; + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/doc/DocumentationActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/doc/DocumentationActivity.java new file mode 100644 index 00000000..cc5b8bd8 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/doc/DocumentationActivity.java @@ -0,0 +1,48 @@ +package com.stardust.scriptdroid.ui.doc; + +import android.app.Activity; +import android.webkit.WebView; + +import com.stardust.scriptdroid.Pref; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.util.BackPressedHandler; +import com.stardust.widget.EWebView; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.EActivity; +import org.androidannotations.annotations.ViewById; + +/** + * Created by Stardust on 2017/10/24. + */ +@EActivity(R.layout.activity_documentation) +public class DocumentationActivity extends BaseActivity { + + public static final String EXTRA_URL = "url"; + + @ViewById(R.id.eweb_view) + EWebView mEWebView; + + WebView mWebView; + + @AfterViews + void setUpViews() { + setToolbarAsBack(getString(R.string.text_tutorial)); + mWebView = mEWebView.getWebView(); + String url = getIntent().getStringExtra(EXTRA_URL); + if (url == null) { + url = Pref.getDocumentationUrl() + "index.html"; + } + mWebView.loadUrl(url); + } + + @Override + public void onBackPressed() { + if (mWebView.canGoBack()) { + mWebView.goBack(); + } else { + super.onBackPressed(); + } + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/doc/ManualDialog.java b/app/src/main/java/com/stardust/scriptdroid/ui/doc/ManualDialog.java new file mode 100644 index 00000000..2062345e --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/doc/ManualDialog.java @@ -0,0 +1,83 @@ +package com.stardust.scriptdroid.ui.doc; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.widget.TextView; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.R; +import com.stardust.widget.EWebView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * Created by Stardust on 2017/10/24. + */ + +public class ManualDialog { + + @BindView(R.id.title) + TextView mTitle; + + @BindView(R.id.eweb_view) + EWebView mEWebView; + + @BindView(R.id.pin_to_left) + View mPinToLeft; + + Dialog mDialog; + private Context mContext; + + public ManualDialog(Context context) { + mContext = context; + View view = View.inflate(context, R.layout.floating_manual_dialog, null); + ButterKnife.bind(this, view); + mDialog = new MaterialDialog.Builder(context) + .customView(view, false) + .build(); + mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + + + public ManualDialog title(String title) { + mTitle.setText(title); + return this; + } + + public ManualDialog url(String url) { + mEWebView.getWebView().loadUrl(url); + return this; + } + + public ManualDialog pinToLeft(View.OnClickListener listener) { + mPinToLeft.setOnClickListener(v -> { + mDialog.dismiss(); + listener.onClick(v); + }); + return this; + } + + public ManualDialog show() { + mDialog.show(); + return this; + } + + @OnClick(R.id.close) + void close() { + mDialog.dismiss(); + } + + @OnClick(R.id.fullscreen) + void viewInNewActivity() { + mDialog.dismiss(); + DocumentationActivity_.intent(mContext) + .extra(DocumentationActivity.EXTRA_URL, mEWebView.getWebView().getUrl()) + .start(); + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/doc/OnlineDocsFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/doc/OnlineDocsFragment.java similarity index 83% rename from app/src/main/java/com/stardust/scriptdroid/ui/main/doc/OnlineDocsFragment.java rename to app/src/main/java/com/stardust/scriptdroid/ui/doc/OnlineDocsFragment.java index fc509e75..99ada24c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/doc/OnlineDocsFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/doc/OnlineDocsFragment.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui.main.doc; +package com.stardust.scriptdroid.ui.doc; import android.app.Activity; import android.content.Context; @@ -8,6 +8,7 @@ import android.support.v4.view.ViewPager; import android.view.View; import android.webkit.WebView; +import com.stardust.scriptdroid.Pref; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.ui.main.ViewPagerFragment; import com.stardust.util.BackPressedHandler; @@ -23,6 +24,8 @@ import org.androidannotations.annotations.ViewById; @EFragment(R.layout.fragment_online_docs) public class OnlineDocsFragment extends ViewPagerFragment implements BackPressedHandler { + public static final String ARGUMENT_URL = "url"; + @ViewById(R.id.eweb_view) EWebView mEWebView; WebView mWebView; @@ -35,7 +38,11 @@ public class OnlineDocsFragment extends ViewPagerFragment implements BackPressed @AfterViews void setUpViews() { mWebView = mEWebView.getWebView(); - mWebView.loadUrl("https://hyb1996.github.io/AutoJs-Docs/"); + String url = Pref.getDocumentationUrl() + "index.html"; + if (getArguments() != null) { + url = getArguments().getString(ARGUMENT_URL, url); + } + mWebView.loadUrl(url); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java index 6c3cb254..47d3ac2a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/CodeMirrorEditor.java @@ -54,7 +54,7 @@ public class CodeMirrorEditor extends FrameLayout { public interface Callback { void onChange(); - void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, String[] list); + void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, String[] list, String[] urls); } private static String[] sAvailableThemes; @@ -388,14 +388,14 @@ public class CodeMirrorEditor extends FrameLayout { } @JavascriptInterface - public void updateCodeCompletion(final int fromLine, final int fromCh, final int toLine, final int toCh, final String[] list) { + public void updateCodeCompletion(final int fromLine, final int fromCh, final int toLine, final int toCh, final String[] list, final String[] urls) { if (mCallback == null) { return; } mWebView.post(new Runnable() { @Override public void run() { - mCallback.updateCodeCompletion(fromLine, fromCh, toLine, toCh, list); + mCallback.updateCodeCompletion(fromLine, fromCh, toLine, toCh, list, urls); } }); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java index 3ccfbb40..087730e9 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java @@ -4,15 +4,18 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.widget.DrawerLayout; import android.view.Menu; import android.view.MenuItem; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.Pref; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.ScriptFile; import com.stardust.scriptdroid.ui.BaseActivity; import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; +import com.stardust.widget.EWebView; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; @@ -31,6 +34,7 @@ public class EditActivity extends BaseActivity { @ViewById(R.id.editor_view) EditorView mEditor; + private EditorMenu mEditorMenu; public static void editFile(Context context, String path) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java index 53eea27b..c9404ce1 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditorView.java @@ -7,7 +7,9 @@ import android.content.IntentFilter; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; +import android.support.v4.widget.DrawerLayout; import android.util.AttributeSet; +import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -17,12 +19,15 @@ import com.stardust.autojs.engine.JavaScriptEngine; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.autojs.script.JavaScriptFileSource; import com.stardust.pio.PFiles; +import com.stardust.scriptdroid.Pref; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.Scripts; +import com.stardust.scriptdroid.ui.doc.ManualDialog; import com.stardust.scriptdroid.ui.edit.completion.CodeCompletions; import com.stardust.scriptdroid.ui.edit.completion.CodeCompletionBar; import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhancedBarColors; import com.stardust.scriptdroid.ui.edit.completion.Symbols; +import com.stardust.widget.EWebView; import com.stardust.widget.ToolbarMenuItem; import com.stardust.widget.ViewSwitcher; @@ -36,7 +41,6 @@ import java.util.Arrays; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers; import static com.stardust.scriptdroid.model.script.Scripts.ACTION_ON_EXECUTION_FINISHED; @@ -45,7 +49,7 @@ import static com.stardust.scriptdroid.model.script.Scripts.ACTION_ON_EXECUTION_ * Created by Stardust on 2017/9/28. */ @EViewGroup(R.layout.editor_view) -public class EditorView extends FrameLayout { +public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintClickListener { public static final String EXTRA_PATH = "Still Love Eating 17.4.5"; public static final String EXTRA_NAME = "Still love you 17.6.29 But....(ಥ_ಥ)"; @@ -69,8 +73,17 @@ public class EditorView extends FrameLayout { @ViewById(R.id.input_method_enhance_bar) View mInputMethodEnhanceBar; - @ViewById(R.id.symbols) - ImageView mSymbols; + @ViewById(R.id.symbol_bar) + CodeCompletionBar mSymbolBar; + + @ViewById(R.id.functions) + ImageView mFunctions; + + @ViewById(R.id.docs) + EWebView mEWebView; + + @ViewById(R.id.drawer_layout) + DrawerLayout mDrawerLayout; private static final String KEY_EDITOR_THEME = "我...深爱着...你呀...17.9.28"; @@ -80,8 +93,6 @@ public class EditorView extends FrameLayout { private ScriptExecution mScriptExecution; private boolean mTextChanged = false; - private CodeCompletions mCodeCompletions; - private boolean mSymbolsShown = false; private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -168,21 +179,15 @@ public class EditorView extends FrameLayout { setUpEditor(); setUpInputMethodEnhancedBar(); setMenuItemStatus(R.id.save, false); + mEWebView.getWebView().getSettings().setDisplayZoomControls(true); + mEWebView.getWebView().loadUrl(Pref.getDocumentationUrl() + "index.html"); + } private void setUpInputMethodEnhancedBar() { - mCodeCompletionBar.setOnHintClickListener(new CodeCompletionBar.OnHintClickListener() { - @Override - public void onHintClick(CodeCompletions completions, int pos) { - if (completions.shouldBeInserted()) { - mEditor.insert(completions.getHints().get(pos)); - showOrHideSymbols(); - return; - } - mEditor.replace(completions.getHints().get(pos), completions.getFrom().line, completions.getFrom().ch, - completions.getTo().line, completions.getTo().ch); - } - }); + mSymbolBar.setCodeCompletions(Symbols.getSymbols()); + mCodeCompletionBar.setOnHintClickListener(this); + mSymbolBar.setOnHintClickListener(this); } @@ -198,11 +203,12 @@ public class EditorView extends FrameLayout { @Override - public void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, final String[] list) { + public void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, final String[] list, final String[] urls) { mCodeCompletionBar.setCodeCompletions(new CodeCompletions( new CodeCompletions.Pos(fromLine, fromCh), new CodeCompletions.Pos(toLine, toCh), - Arrays.asList(list) + Arrays.asList(list), + Arrays.asList(urls) )); } }); @@ -215,30 +221,19 @@ public class EditorView extends FrameLayout { mInputMethodEnhanceBar.setBackgroundColor(InputMethodEnhancedBarColors.getBackgroundColor(theme)); int textColor = InputMethodEnhancedBarColors.getTextColor(theme); mCodeCompletionBar.setTextColor(textColor); - mSymbols.setColorFilter(textColor); + mSymbolBar.setTextColor(textColor); + mFunctions.setColorFilter(textColor); } - @Click(R.id.symbols) - void showOrHideSymbols() { - if (mSymbolsShown) { - mCodeCompletionBar.setCodeCompletions(mCodeCompletions); - mCodeCompletions = null; - } else { - mCodeCompletions = mCodeCompletionBar.getCodeCompletions(); - mCodeCompletionBar.setCodeCompletions(Symbols.getSymbols()); - } - mSymbolsShown = !mSymbolsShown; + @Click(R.id.functions) + void showFunctionList() { + } @Click(R.id.run) public void runAndSaveFileIfNeeded() { save().observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Consumer() { - @Override - public void accept(@io.reactivex.annotations.NonNull String s) throws Exception { - run(); - } - }); + .subscribe(s -> run()); } public void run() { @@ -261,19 +256,11 @@ public class EditorView extends FrameLayout { public Observable save() { return mEditor.getText() .observeOn(Schedulers.io()) - .doOnNext(new Consumer() { - @Override - public void accept(@io.reactivex.annotations.NonNull String s) throws Exception { - PFiles.write(mFile, s); - } - }) + .doOnNext(s -> PFiles.write(mFile, s)) .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(new Consumer() { - @Override - public void accept(@io.reactivex.annotations.NonNull String s) throws Exception { - mTextChanged = false; - setMenuItemStatus(R.id.save, false); - } + .doOnNext(s -> { + mTextChanged = false; + setMenuItemStatus(R.id.save, false); }); } @@ -337,15 +324,12 @@ public class EditorView extends FrameLayout { new MaterialDialog.Builder(getContext()) .title(R.string.text_editor_theme) .items((CharSequence[]) themes) - .itemsCallbackSingleChoice(i, new MaterialDialog.ListCallbackSingleChoice() { - @Override - public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) { - PreferenceManager.getDefaultSharedPreferences(getContext()).edit() - .putString(KEY_EDITOR_THEME, text.toString()) - .apply(); - setTheme(text.toString()); - return true; - } + .itemsCallbackSingleChoice(i, (dialog, itemView, which, text) -> { + PreferenceManager.getDefaultSharedPreferences(getContext()).edit() + .putString(KEY_EDITOR_THEME, text.toString()) + .apply(); + setTheme(text.toString()); + return true; }) .show(); } @@ -369,4 +353,31 @@ public class EditorView extends FrameLayout { public void replaceAll(String keywords, String replacement, boolean usingRegex) { mEditor.replaceAll(keywords, replacement, usingRegex); } + + @Override + public void onHintClick(CodeCompletions completions, int pos) { + if (completions.shouldBeInserted()) { + mEditor.insert(completions.getHints().get(pos)); + showFunctionList(); + return; + } + mEditor.replace(completions.getHints().get(pos), completions.getFrom().line, completions.getFrom().ch, + completions.getTo().line, completions.getTo().ch); + } + + @Override + public void onHintLongClick(CodeCompletions completions, int pos) { + String url = completions.getUrltAt(pos); + if (url == null) + return; + String absUrl = Pref.getDocumentationUrl() + url; + new ManualDialog(getContext()) + .title(completions.getHints().get(pos)) + .url(absUrl) + .pinToLeft(v -> { + mEWebView.getWebView().loadUrl(absUrl); + mDrawerLayout.openDrawer(Gravity.START); + }) + .show(); + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/ViewSampleActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/ViewSampleActivity.java index cb8aba5b..709f0387 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/ViewSampleActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/ViewSampleActivity.java @@ -20,7 +20,6 @@ import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.model.sample.Sample; import com.stardust.scriptdroid.ui.BaseActivity; import com.stardust.scriptdroid.ui.common.ScriptOperations; -import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity; import com.stardust.theme.ThemeColorManager; import com.stardust.util.AssetsCache; import com.stardust.util.SparseArrayEntries; @@ -145,7 +144,7 @@ public class ViewSampleActivity extends AppCompatActivity implements OnActivityR showLog(); return true; case R.id.action_help: - HelpCatalogueActivity.showMainCatalogue(this); + return true; case R.id.action_import: new ScriptOperations(this, mView) diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletionBar.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletionBar.java index d49ef1fe..211b41e7 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletionBar.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletionBar.java @@ -40,6 +40,8 @@ public class CodeCompletionBar extends RecyclerView { public interface OnHintClickListener { void onHintClick(CodeCompletions completions, int pos); + + void onHintLongClick(CodeCompletions completions, int pos); } private int mTextColor; @@ -64,8 +66,9 @@ public class CodeCompletionBar extends RecyclerView { int position = getChildViewHolder(v).getAdapterPosition(); if (position < 0 || position >= mCodeCompletions.getHints().size()) return false; - ClipboardUtil.setClip(getContext(), mCodeCompletions.getHints().get(position)); - Toast.makeText(getContext(), R.string.text_copied, Toast.LENGTH_SHORT).show(); + if (mOnHintClickListener != null) { + mOnHintClickListener.onHintLongClick(mCodeCompletions, position); + } return true; } }; @@ -120,7 +123,7 @@ public class CodeCompletionBar extends RecyclerView { public void onBindViewHolder(ViewHolder holder, int position) { TextView textView = ((TextView) holder.itemView); textView.setText(mCodeCompletions.getHints().get(position)); - if(mTextColor != 0){ + if (mTextColor != 0) { textView.setTextColor(mTextColor); } } @@ -140,29 +143,6 @@ public class CodeCompletionBar extends RecyclerView { } } - private static void readCompletions(Context context, String path) { - try { - JsonParser parser = new JsonParser(); - JsonObject object = parser.parse(new InputStreamReader(context.getAssets().open(path))).getAsJsonObject(); - //InputMethodEnhanceBar.global = readGlobal(object.remove("global").getAsJsonObject()); - readModules(object); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - private static void readModules(JsonObject object) { - for (Map.Entry module : object.entrySet()) { - //variables.put(module.getKey(), GsonUtils.toStringList(module.getValue())); - } - } - - private static List readGlobal(JsonObject global) { - List globalFunctions = new ArrayList<>(); - for (Map.Entry moduleGlobal : global.entrySet()) { - globalFunctions.addAll(GsonUtils.toStringList(moduleGlobal.getValue())); - } - return globalFunctions; - } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletions.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletions.java index f761d427..a1dccadb 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletions.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/CodeCompletions.java @@ -5,7 +5,7 @@ import java.util.List; /** * Created by Stardust on 2017/9/27. */ - +// TODO: 2017/10/24 refactor public class CodeCompletions { public static class Pos { @@ -21,15 +21,17 @@ public class CodeCompletions { private Pos mFrom; private Pos mTo; private List mHints; + private List mUrls; - public CodeCompletions(Pos from, Pos to, List hints) { + public CodeCompletions(Pos from, Pos to, List hints, List urls) { mFrom = from; mTo = to; mHints = hints; + mUrls = urls; } public static CodeCompletions just(List hints) { - return new CodeCompletions(null, null, hints); + return new CodeCompletions(null, null, hints, null); } public Pos getFrom() { @@ -40,6 +42,12 @@ public class CodeCompletions { return mTo; } + public String getUrltAt(int pos) { + if (mUrls == null) + return null; + return mUrls.get(pos); + } + public List getHints() { return mHints; } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/Symbols.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/Symbols.java index 07eef995..d5def61d 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/Symbols.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/completion/Symbols.java @@ -9,8 +9,8 @@ import java.util.Arrays; public class Symbols { private static CodeCompletions sSymbols = CodeCompletions.just(Arrays.asList( - "=", "\"", "(", ")", "{", "}", ";", "!", "|", "&", "[", "]", "/", "\\", - "<", ">")); + "\"", "(", ")", "=", ";", "/", "{", "}", "!", "|", "&", "-", + "[", "]", "+", "-", "<", ">", "\\", "*", "?")); public static CodeCompletions getSymbols() { return sSymbols; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentationActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentationActivity.java deleted file mode 100644 index 3a6c2ab9..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentationActivity.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.stardust.scriptdroid.ui.help; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.webkit.WebView; - -import com.stardust.pio.PFiles; -import com.stardust.scriptdroid.ui.BaseActivity; -import com.stardust.theme.ThemeColorManagerCompat; -import com.stardust.util.UnderuseExecutors; -import com.stardust.widget.CommonMarkdownView; -import com.stardust.scriptdroid.R; -import com.wang.avi.AVLoadingIndicatorView; - -import java.io.IOException; - -/** - * Created by Stardust on 2017/2/1. - */ - - -public class DocumentationActivity extends BaseActivity { - - private CommonMarkdownView mCommonMarkdownView; - - public static void openDocumentation(Context context, String title, String assetPath) { - context.startActivity(new Intent(context, DocumentationActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra("title", title) - .putExtra("path", assetPath)); - } - - private volatile String mDocumentation; - private String mTitle; - private AVLoadingIndicatorView mLoadingIndicatorView; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setUpUI(); - handleIntent(getIntent()); - setToolbarAsBack(mTitle); - } - - private void handleIntent(Intent intent) { - mTitle = intent.getStringExtra("title"); - final String path = intent.getStringExtra("path"); - if (path == null) - return; - UnderuseExecutors.execute(new Runnable() { - @Override - public void run() { - try { - mDocumentation = PFiles.read(getAssets().open("help/" + path)); - } catch (IOException e) { - e.printStackTrace(); - } - runOnUiThread(new Runnable() { - @Override - public void run() { - loadDocument(); - } - }); - } - }); - - } - - private void setUpUI() { - setContentView(R.layout.activity_document); - setUpLoadingView(); - } - - private void setUpLoadingView() { - mLoadingIndicatorView = $(R.id.loading); - mLoadingIndicatorView.setIndicatorColor(ThemeColorManagerCompat.getColorPrimary()); - } - - private void loadDocument() { - mCommonMarkdownView = $(R.id.markdown); - mCommonMarkdownView.setOnPageFinishedListener(new CommonMarkdownView.OnPageFinishedListener() { - @Override - public void onPageFinished(WebView view, String url) { - mLoadingIndicatorView.hide(); - } - }); - try { - mCommonMarkdownView.loadMarkdown(mDocumentation); - } catch (Exception e) { - e.printStackTrace(); - mCommonMarkdownView.setText(R.string.text_load_failed); - } - } - - @Override - public void onBackPressed() { - if (mCommonMarkdownView.canGoBack()) { - mCommonMarkdownView.goBack(); - } else { - super.onBackPressed(); - } - } - -} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/help/HelpCatalogueActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/help/HelpCatalogueActivity.java deleted file mode 100644 index 8e7777a6..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/ui/help/HelpCatalogueActivity.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.stardust.scriptdroid.ui.help; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Keep; -import android.support.annotation.Nullable; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import android.workground.WrapContentLinearLayoutManager; - -import com.stardust.pio.PFiles; -import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.ui.BaseActivity; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.stardust.scriptdroid.R; -import com.stardust.theme.ThemeColorManagerCompat; -import com.stardust.util.UnderuseExecutors; -import com.wang.avi.AVLoadingIndicatorView; - -import org.json.JSONObject; - -import java.io.IOException; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Created by Stardust on 2017/3/6. - */ - -public class HelpCatalogueActivity extends BaseActivity { - - - public static void showCatalogue(Context context, String title, String catalogue) { - context.startActivity(new Intent(context, HelpCatalogueActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra("title", title) - .putExtra("catalogue", catalogue)); - } - - public static void showMainCatalogue(Context context) { - context.startActivity(new Intent(context, HelpCatalogueActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - } - - private static Map> CATALOGUES; - - private static class Item extends JSONObject { - - String title; - String summary; - @Keep - private String type; - @Keep - private String path; - - Item(String title, String summary) { - this.title = title; - this.summary = summary; - } - - Item(String title) { - this(title, null); - } - - void redirect(Context context) { - switch (type) { - case "markdown": - DocumentationActivity.openDocumentation(context, title, path + "/" + title + ".md"); - break; - case "catalogue": - showCatalogue(context, title, title); - break; - case "html": - LocalWebViewActivity.openAssetsHtml(context, title, path + "/" + title + ".html"); - break; - } - - } - } - - List mItems; - private RecyclerView mRecyclerView; - private AVLoadingIndicatorView mLoadingIndicatorView; - private String mTitle; - private View.OnClickListener mOnItemClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v); - if (holder != null) { - mItems.get(holder.getAdapterPosition()).redirect(HelpCatalogueActivity.this); - } - } - }; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setUpUI(); - if (CATALOGUES == null) { - readCatalogues(); - } else { - onCataloguesAvailable(); - } - } - - private void onCataloguesAvailable(){ - mLoadingIndicatorView.hide(); - handleIntent(); - setToolbarAsBack(mTitle); - } - - private void readCatalogues() { - UnderuseExecutors.execute(new Runnable() { - @Override - public void run() { - readCatalogues("help/catalogue.json"); - runOnUiThread(new Runnable() { - @Override - public void run() { - onCataloguesAvailable(); - } - }); - } - }); - } - - private void handleIntent() { - String catalogue = getIntent().getStringExtra("catalogue"); - if (catalogue == null) - catalogue = "main"; - mTitle = getIntent().getStringExtra("title"); - if (mTitle == null) - mTitle = getString(R.string.text_help); - mItems = CATALOGUES.get(catalogue); - mRecyclerView.setAdapter(new Adapter()); - } - - private void setUpUI() { - setContentView(R.layout.activity_help); - setUpRecyclerView(); - setUpLoadingView(); - } - - private void setUpRecyclerView() { - mRecyclerView = $(R.id.catalogue); - mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(this)); - mRecyclerView.addItemDecoration(new DividerItemDecoration(this, RecyclerView.VERTICAL)); - } - - private void setUpLoadingView() { - mLoadingIndicatorView = $(R.id.loading); - mLoadingIndicatorView.setIndicatorColor(ThemeColorManagerCompat.getColorPrimary()); - } - - private class Adapter extends RecyclerView.Adapter { - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - int view = R.layout.activity_help_catalogue_item; - return new ViewHolder(LayoutInflater.from(HelpCatalogueActivity.this).inflate(view, parent, false)); - } - - @Override - public void onBindViewHolder(ViewHolder holder, int position) { - Item item = mItems.get(position); - holder.title.setText(item.title); - if (item.summary != null) { - holder.summary.setVisibility(View.VISIBLE); - holder.summary.setText(item.summary); - } else { - holder.summary.setVisibility(View.GONE); - } - } - - @Override - public int getItemCount() { - return mItems.size(); - } - - } - - private class ViewHolder extends RecyclerView.ViewHolder { - - TextView title, summary; - - ViewHolder(View itemView) { - super(itemView); - itemView.setOnClickListener(mOnItemClickListener); - title = (TextView) itemView.findViewById(R.id.title); - summary = (TextView) itemView.findViewById(R.id.summary); - } - } - - private static void readCatalogues(String path) { - Map> fromJson; - try { - String json = PFiles.read(App.getApp().getAssets().open(path)); - Gson gson = new Gson(); - Type type = new TypeToken>>() { - }.getType(); - fromJson = gson.fromJson(json, type); - } catch (IOException e) { - fromJson = new HashMap<>(); - e.printStackTrace(); - } - CATALOGUES = fromJson; - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/help/LocalWebViewActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/help/LocalWebViewActivity.java deleted file mode 100644 index ff88a28b..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/ui/help/LocalWebViewActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.stardust.scriptdroid.ui.help; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.webkit.WebView; - -import com.stardust.pio.PFiles; -import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.ui.BaseActivity; - -import java.io.IOException; - -/** - * Created by Stardust on 2017/3/14. - */ - -public class LocalWebViewActivity extends BaseActivity { - - // TODO: 2017/3/14 缓存asset - - private String mTitle; - private String mHtml; - private WebView mWebView; - - public static void openAssetsHtml(Context context, String title, String path) { - context.startActivity(new Intent(context, LocalWebViewActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra("title", title) - .putExtra("path", path)); - } - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - handleIntent(getIntent()); - setUpUI(); - } - - private void handleIntent(Intent intent) { - mTitle = intent.getStringExtra("title"); - String path = intent.getStringExtra("path"); - if (path != null) - try { - mHtml = PFiles.read(getAssets().open("help/" + path)); - } catch (IOException e) { - e.printStackTrace(); - mHtml = getString(R.string.text_load_failed); - } - } - - private void setUpUI() { - setContentView(R.layout.activity_local_webview); - setToolbarAsBack(mTitle); - loadHtml(); - } - - private void loadHtml() { - mWebView = $(R.id.webView); - try { - mWebView.loadDataWithBaseURL(null, mHtml, "text/html", "utf-8", null); - } catch (Exception e) { - e.printStackTrace(); - mWebView.loadDataWithBaseURL(null, getString(R.string.text_load_failed), "text/html", "utf-8", null); - } - } - - @Override - public void onBackPressed() { - if (mWebView.canGoBack()) { - mWebView.goBack(); - } else { - super.onBackPressed(); - } - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java index febc149b..f9cc2d53 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java @@ -28,10 +28,10 @@ import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.ui.common.NotAskAgainDialog; import com.stardust.scriptdroid.ui.common.ScriptOperations; +import com.stardust.scriptdroid.ui.doc.OnlineDocsFragment_; import com.stardust.scriptdroid.ui.floating.FloatyWindowManger; import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.ui.main.community.CommunityFragment_; -import com.stardust.scriptdroid.ui.main.doc.OnlineDocsFragment_; import com.stardust.scriptdroid.ui.main.scripts.MyScriptListFragment_; import com.stardust.scriptdroid.ui.main.task.TaskManagerFragment_; import com.stardust.theme.ThemeColorManager; diff --git a/app/src/main/java/com/stardust/widget/EWebView.java b/app/src/main/java/com/stardust/widget/EWebView.java index db875f82..980b5152 100644 --- a/app/src/main/java/com/stardust/widget/EWebView.java +++ b/app/src/main/java/com/stardust/widget/EWebView.java @@ -140,7 +140,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.startsWith("http://") || url.startsWith("https://")) { + if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://")) { view.loadUrl(url); } else { getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); diff --git a/app/src/main/res/drawable/ic_ali_close.png b/app/src/main/res/drawable/ic_ali_close.png new file mode 100644 index 0000000000000000000000000000000000000000..715097d53fcc0498e6b96db52f4b577245b99efd GIT binary patch literal 976 zcmV;>126oEP)do_2yHC9U@P$w5tUdZhr}fB?#%4W?Cj3}fvv(ECi~;O5J&<_ zDWz80((tv@zznbz_z2ts7IR#x(hdW&z)oNRxDR}GIk*pa3M{RAJ^^P_+*EO!jqiIA zm~%P&WRt`8`~fb;zi+i|2Ocx|eJ=s$ng&d_9JWVjae7GmyMEI&;JU*AZCdwSHf!y( zYto<_9z%o{mM>N#*sSLuq4^bp^}cD~PT;NQK%u!6g0%!(Ya4tN_#QA=Xw5ys|D8T} z9ex7%<~dxOwt1nO^@8P3Jm-Ygy=+*P(89}(WeLr{-mom8xz{_ECA9X6!Lo!lx#F-a zp>3>KEK6vs6^~^JZ9rI7&1i$evT8&dES6Oh+TgLQ8qh|AWrd<$=;N}UjSkBSLHkYF zXrsll#)LL{ENcvC)nHjeMyn3X8X{V?Sk{oxs>ia1fF`VUm5e5=36+Q@td>eb6P9Bo zpb5*fKGB2~SRZJ@>R3)RVMQtjny@055=~f%N`WS<#KlAtR;FU02`h75(1g`fCkgwT z>-m5)FMz2$-`2Pb*)(ld&!t2YR-#g%2`h0i(S(($7-+)ETo*K9_0%)Mz%KW3*_zu1 zJRtnzu!qE9|32D7FZW7`!Cef z_@iml0*ZlU2`zCku`Hn_Dg~A$w8*8zvV<0?99WjnI+hd55?Ww=U|B-*tWPXUXpWVD zWeKgNlCUhHO{hdHOK9sV8OsvdN<+Z1Leb7=zGt$Agk^=G{bB@YL&UPGLmM)dRSnu0 zu&mLejS0&dE!r5dtkI#38Os_CS`Ap%;L&QrvIdJ*BbGHdw3@N3!Jr9iwc^o)wXtH+ zgf+S1(1g`qF=)bauXi+I`PUnou)@oZCamsdLlaiKlA{SLeo4`8c@7qqTOnvafrCv$ z4|xt0mS3lUMf~3H%cg;Ip2LLYpYNvq1$ImtcGF|fJg_^#H&jEuo3?+_pev38v{~JA z-Lx-FL-qq-TLx&e;^newciVA~Va09+SYY$_{SMgUGUPb$dd0000046=7RK+r+(>R%Vge{C1PloVLneFEM+N`B`T80D2%cwqDH7BsaTM*syI=?WHNund^qR4&w1Y8bI$p6F8g@7>R|R_ z007WoyD|OLmHWRy?@;Gq$MDAhuw#+UWSq(lUHL(EZTi^G!Xga*xZ6R~n}8ofz$@1k zK&6<Kl>D>qR=7NKGs3#k<<}-vxXDCMYmT&+97n%r7S9h75Q{kgqoYHfwKq6G*^i0wgavR~ zZ#*w41tqDUq>8g~b@C95h$;>OJ!K(UPRK(y9}Sg%VvFw-l6U*0VU2EZw%y_ZXIkFa z=()~?`2Zr&I35vSD&I$5)U?Suuajq=;W^<@jR6#G0C_Zg=|dJRZ~CDpV00D#5o|af ztEFrJ0_lO=!OCh*1KhEG2dy4v2wKXr^tkwsH6l!YAV^`DAeQp1-CVrHougAw3{;C; zc!c#L#0i-pEusqAfNG}$3~$9SN&sizKNfz&0^EJf#c0Jd^))ewi@50^K>qqGv76$V z+97qf+Ivq6q=)vHxD3MzH_)FjCiAmvh+j(;(5$tBZoBpY?jQG9^ z^_d^h@N5l<8g`Xb!gj%G4|WH1jdUNMo&BblU*skG<@SC-Yd>Gb zoR7|cXE4_ZJw}9ADx?t_hX1+4%H?!9=okG4=3vspg?z$Q@O{g zm@ZwO`m29%!0X{K7PkR*<7{ME9DcKH1$|x14M!AIq}zkbrk zo4Zm)OX_1=r+d9l3UvinHFmf1^i47BNIMGmNV4x0UoM4IvmyWV{@puq~95*m8yCie4CM7@4U(lV##+E12hOY7m{&GwZ9a?y#?BuPF7^y?~J**I33#$97WclUoR z)5BUMh8ovD%1PQ5ps-#Xv%-_)`l6J4wuArH7=d^_G&Y6q$F1v++b_V$E)3uYcFG#$ zleL`Nz$Mk@j>B&I*nw71E^=Z9aZZ#{F}+lFNa6$ zm!*xus8w0F_Y+GX_j|=tihMGVVJ0p))$2ikpIg^Um37~~`_xfmnzPFTM2Bgf@_*zB zQPqn7OUKpA@GkYv`$lW0#__k%>oFk-QxR`{JbWfP;;Ud9#9{d&N^JZ5SX%7FHZPX} zS#JI`cLr{A489JSAFX9~OC*YjxWoIfH>s;^;Fc^kq`fU}d~YkE#4R=6v1iX5>@*ww zRj>(eE6X6x?9R&~C>^`ep+_mP-

5t|FGpR4+f_?n+Xfu;Uw+?rH*=tAgZx1_}2s6$bdpy X^GU$co8@ds{rUhl%Zu6R%;EhPIjkI7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_ali_fx.png b/app/src/main/res/drawable/ic_ali_fx.png new file mode 100644 index 0000000000000000000000000000000000000000..206c22b4c0d8f83160697798d5eecf5b2d4a497e GIT binary patch literal 2691 zcmaJ@dpHyN8~<)&h8(kyLuJw^jVva23lo#M%O%B}QbuykAuN|%${{kETR%;6i`5Y# z%%wUmwcH&kL_#6UC5-*_{Qmzv@AJN&=e_>(dEe)GQ|!p6CB)>#000tJmgWw-Nc*J- z_^xd?_U;BijAUhg$|>UfLc!KEbu(nrmIV!ggd8FW<@^tlX$rr*WFUox4qgAI_i8N0 zX)tuDEM~>sx4Lxm!oV@e4*W{Bz}^t&on|c;k!%19PYeezv)k% zgzpy-lib2qO)a4NLGc#S7nEo)Uh|hs5pq#0v4TrTQY+65G3j{4S91Fjgm!DAH0d$!x7z|?rN7yt z=TU26y#a7wd0*1(d|G{kTuRZg`c(@ABXO#RaU9%U z$+M;xLMur>m{TKZinySv|LKQGw&C=Q1QsAt2A?XhHWXe8%`Q6Gi69}59JVToscwvl zuBC@0uwqQvlIyaOQpfD9Z{y&iQeQ@S&~grsZ>GC}i!O`|Ci4S*NT|;_d5?RYFGrY* z(pr-ySyymhO>_#`$0w(JwwB@bRk>Uh3nALT{CMs^otPi00V^M@_wDJpI@Ua;avDba zymFmYS7MpHq96h4gP7s?#}%BkOFo&+$`FDA`=+t*An%Ev_bd&jARCRj}M%ew_baGqh5v3C5vp zx1YMg^Tl309o}yMutP068(P|kND&(5r&jbzVESw!gy6oW+P<8xzY)Sb%LVL?ou&JH zCFA9pNjgqgdEhs@xS^*~C{}Vd{(DY-oiDhyiBH^*~*qgyA7xX;POL z(cgx}m9JSpUQN)xugpFX>tV3Zs@|R%z@P?h`I^vMqhP?QAQRD# zvg#j4DO);=QD;i3Yjtq1Z#aBN_-8Jwp?4)id|3!oc(5>`RV^<3VJA0v=L{cX^d-;t zQFk12JQNo-BcVXHl36TbCbCZI*Zg*PeGS*eY;cX*vV3~}N`~5JNQnlkgNIoJXeDGc zw%25#lU`Yp*mUSF^k@|92^W$I(S_5Jf^}_C1k=z8Mri^6NtM~t*ZW;VdQ_VV8Xlau zvrFPR+4icA(vbyaGI~?ClNRaqc+^0wM||&cfBKs)zSHv?Icgl#cE9^DW`;$M{q_<` zr)1|IW0XfiL!W1H|8}S=Imo2gs&RssVbB5cPDg00T8F>qkApS7x!fHey{y-%vxVS6 z^jXQg>H@x1VtI(pEuxseANuUl5#ezEn7W$}@_%C7AB740RAVV<>>F=&_Yyz7RTq>E zF$7z`cEmgKE*Ls&zmR8wQ($T*g)Nk|Kk$y}EDXxoLsB0JPW2n-r_6=S?U%(P9}=Bs zv`!sIaZCxFQL(A2e+;)C+NqnA1&YHi1sg^XPUhiq8}`ULEV<6Q`GD6dTnAZ`{D-k& zqll=NO?^b;M*Kwq!(w`DlYZw+yRtx`4+gNkEn3b-ECl0s{~(_{#lC}J0<#e!E9Zi@ z`YMiLKI$1f{F!*H z>t%XhSS>V!amuywq^xZ|d=YVd825&-@H>#LaFf4Z!LeRdu9SIkX5frO1e}K193Jp; z_?s_)y`}$k@~;1Rh?h*Zjpw7iK)3tGqbkplPx`3KX$4V2p%OFgl}=?NqUSaxggw-* zQdMKgQfoT(vOnscIi&|i7~=eg%y?h0AlL$%qDF!CaeD)(Wrfl_1n53Cu9U%=wk0P9 zxRGw(J?0FnfA`w&kRkJnMn=I5(5$yj_a;vPw37f5uT(ILGc25a@@}60D}N7>=Jq|mc7!^w-DC0)9w7-PPRV~aS<5V?1TgmjSI^>KMbe|H z6y1#*j9U1QI^B3-ex~I`T>Pvsp!Y3}eo~Bk)G@mzd;G9aPkPGsn1Vj3=c$EB2v_E! zWE0?I^2^kBLckH6U9fG-${y=8=+&O$*>QLzgqAa%{t{i$dgG_PwOFY?QWCJQz98~W zH`3jEsxOMO5Bl%z48xxkR-#Ya9^LPbsw*4EznWc+zA>b?K9#FDbEUt-&@7B+R0gbh ztlHHU-#DR+5yevRIRjz*#DtKK_&%Sg%wkuErWBYNEsMX1##jc^yFg z_ksAWpt-aomZqRP(q_RAxZbIf9g4jZQ7MrJo}8(to8$&_Z)u}-o}}wt>+;q`OMl%Q zD6Zb!!;O9i{&?1NjhO}%kdLP-yHJ;x;*PGL>&OP|!?6s{yA7(nMsLC}0K2?I@qfQJ zD9W`v8@!9*IWsOS-CVpn6d?n!or+dCrb64=(~Ju6z-A}Evu3sJw)N1TGN7ijC~9LT zM{}~vsv6KrRy=}#|3uOcH&~Ye86BhRLNZ@!8$Y)tinl<)=(O!Z`M7xJLZF{0`1wuL zWoxZ`KwX1uXQ6O=C{+-)soODW zqiVF#JY|Q7uACHRhmM_kaWmTM$n})qmJcuaw{wd^VCws%*}}CX=Z=_f4ZNTVxr`N$ z#g9bvKSby<+^cjZF7A>-_vo-)h5fjL1}E6Mq{b=EP&$EeTj zl{+2QSAa99&DR36UQyH(j2IT&JEHw_NgTv$)z>r$(@=?UK{Ukc8a$`A4%ijHn`k)> l_Pm|wTayJOX?gy7ED#Vhi`cq9Vs@WPU_~UGSDAXn{TD<==B@w$ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_ali_pin_to_left.png b/app/src/main/res/drawable/ic_ali_pin_to_left.png new file mode 100644 index 0000000000000000000000000000000000000000..5963bf99d97c0b2a6b803ddad9521821b45e4825 GIT binary patch literal 1091 zcmWlZdoY?n%)g9g|v%Xj;CUaah>g_;-n^ zk*^jFbX?Rs%Lz;PYQe<4ke)`4c2`b{-6(H5^T`lXXD_Q*juIqZdR^Q1YZjxj{W2Pk zC+K}KSuOI3L^W&2)-b`v;M}CNJ!ze_$qg&}B+8K7&sH4Fob^DW!y}R;k+MyiUiJTh zqLrQ)DWvOiLXPh=sO@VHh7)AIA1M@gvG-8PSEx+NTxO`q+;_@9}bVC=MT)TA3%D!f{6xRuIoAYtU_Vlqx)?g zk3>a-su2zf{OjL2I^OV-nukeJwy)$N(5DGh&^sC{04p>M(EF*jz(^<9z}JaRBdhDG ztajw-y%VoN5KH6UgWyBah$YC>5Fl_Jr$KNn#&Uv3!Uqua$u%&cyp?J>BBjy>;^-qz zP;*vUx^5yz_Q|}vmVqzBEdyyr3TT^=1p2~A0CgS4pyKCSY^b;< z;6sH26cr76bh5h3yuKOgqh>5*oNqOBeZAGlSBW27SNQwA^3^WwWi5+!)gj8e`GHf2 zx5+D^*KbZXdsna4&1qR}zjrU5ET!v@8ceaK+)0(4z0NOR9G5WjY^&I5D_tVr$sV25 zd1T%&Xh;5Zcx&UBna|ni{jYf1EBVm4ia;Ejv9WRqO&rd}FqcE>KQ0l8!YI)RHIa0+ zzAEcHjX?{rHTK#$G7DcAwJa{Pu+2z8!Y?#-2xlg@vd{riynv2q0k6V|V0YPJIMc0F z1a_Ff3G9_{DiSg^Y@mZ$-vB$h1?YamI0apmJWVAbVaHhw0lA!Qs)osP=N8fXw4*I# z0HqTQ#4Nm@YQZ0C0M|Dq0Pfin3*av;9|KaMu>m{98OqC^lY#5^#gL2RoHcw#I0M%E zd>^7=dJdu$e2Vnk0+d6pab@DWWG?6wVU$VJb>Ig{1la?fFR8Av&Mk}JnJ8iRn@FaT zYQ*)Bar*@$UIsoIBM;h&RAMex6;~f zE4?eUWXm;jN2B)0M8}t3V`+P};Xf{XKD*zKcR_#i+v=Hjref6YKb^k)Pw!B)*B13j WQ|>et-CG5(0tyR`2vQ3rh5rLtp~oNq literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_document.xml b/app/src/main/res/layout/activity_documentation.xml similarity index 59% rename from app/src/main/res/layout/activity_document.xml rename to app/src/main/res/layout/activity_documentation.xml index 6445c6ff..50cba729 100644 --- a/app/src/main/res/layout/activity_document.xml +++ b/app/src/main/res/layout/activity_documentation.xml @@ -20,26 +20,9 @@ - - - - - - - - - + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/editor_view.xml b/app/src/main/res/layout/editor_view.xml index 2e93b454..f3bd2d5a 100644 --- a/app/src/main/res/layout/editor_view.xml +++ b/app/src/main/res/layout/editor_view.xml @@ -109,33 +109,65 @@ - + android:layout_height="match_parent"> - - - - - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/floating_manual_dialog.xml b/app/src/main/res/layout/floating_manual_dialog.xml new file mode 100644 index 00000000..0c4e8362 --- /dev/null +++ b/app/src/main/res/layout/floating_manual_dialog.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file