Пример #1
0
 def expand_menu() -> None:
     run_js(
         f"""
         $(".container-menu-collapsed").removeClass("container-menu-collapsed");
         $("#pywebio-scope-content").addClass("container-content-collapsed");
     """
     )
Пример #2
0
 def append(self, text: str) -> None:
     if text:
         run_js("""$("#{dom_id}>code").append(text);
         """.format(dom_id=self.id),
                text=str(text))
         if self.keep_bottom:
             self.scroll()
Пример #3
0
 def active_button(position, value) -> None:
     run_js(
         f"""
         $("button.btn-{position}").removeClass("btn-{position}-active");
         $("div[style*='--{position}-{value}--']>button").addClass("btn-{position}-active");
     """
     )
Пример #4
0
 def index():
     if key != '' and not login(key):
         logger.warning(f"{info.user_ip} login failed.")
         time.sleep(1.5)
         run_js('location.reload();')
         return
     AlasGUI().run()
Пример #5
0
def on_task_exception(self):
    logger.exception("An internal error occurred in the application")
    toast_msg = ("应用发生内部错误" if "zh" in session_info.user_language else
                 "An internal error occurred in the application")

    e_type, e_value, e_tb = sys.exc_info()
    lines = traceback.format_exception(e_type, e_value, e_tb)
    traceback_msg = "".join(lines)

    traceback_console = Console(color_system="truecolor",
                                tab_size=2,
                                record=True,
                                width=90)
    with traceback_console.capture():  # prevent logging to stdout again
        traceback_console.print_exception(word_wrap=True,
                                          extra_lines=1,
                                          show_locals=True)

    if State.theme == "dark":
        theme = DARK_TERMINAL_THEME
    else:
        theme = LIGHT_TERMINAL_THEME

    html = traceback_console.export_html(theme=theme,
                                         code_format=TRACEBACK_CODE_FORMAT,
                                         inline_styles=True)
    try:
        popup(title=toast_msg, content=put_html(html), size=PopupSize.LARGE)
        run_js(
            "console.error(traceback_msg)",
            traceback_msg="Internal Server Error\n" + traceback_msg,
        )
    except Exception:
        pass
Пример #6
0
def target():
    run_js("$('#markdown-body>.alert-warning').remove()")
    template.basic_output()
    template.background_output()

    run_as_function(template.basic_input())
    actions(buttons=['Continue'])
    template.background_input()
Пример #7
0
 def extend(self, text):
     if text:
         run_js(
             """$("#pywebio-scope-{scope}>div").append(text);
         """.format(scope=self.scope),
             text=str(text),
         )
         if self.keep_bottom:
             self.scroll()
Пример #8
0
 def pin_remove_invalid_mark(keys) -> None:
     if isinstance(keys, str):
         keys = [keys]
     js = ''.join([
         f"""$(".form-control[name='{key}']").removeClass('is-invalid');"""
         for key in keys
     ])
     if js:
         run_js(js)
Пример #9
0
def main():
    """PyWebIO聊天室
    和当前所有在线的人聊天
    """
    global chat_msgs
    run_js("alert('233')")
    put_markdown(
        "## PyWebIO聊天室\n欢迎来到聊天室,你可以和当前所有在线的人聊天。你可以在浏览器的多个标签页中打开本页面来测试聊天效果。"
        "本应用使用不到80行代码实现,源代码[链接](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)",
        lstrip=True)

    msg_box = output()
    put_scrollable(msg_box, height=300, keep_bottom=True)
    nickname = input("请输入你的昵称",
                     required=True,
                     validate=lambda n: '昵称已被使用'
                     if n in online_users or n == '📢' else None)

    online_users.add(nickname)
    chat_msgs.append(
        ('📢', '`%s`加入聊天室. 当前在线人数 %s' % (nickname, len(online_users))))
    msg_box.append(
        put_markdown('`📢`: `%s`加入聊天室. 当前在线人数 %s' %
                     (nickname, len(online_users))))

    @defer_call
    def on_close():
        online_users.remove(nickname)
        chat_msgs.append(
            ('📢', '`%s`退出聊天室. 当前在线人数 %s' % (nickname, len(online_users))))

    refresh_task = run_async(refresh_msg(nickname, msg_box))

    while True:
        data = input_group('发送消息', [
            input(name='msg', help_text='消息内容支持行内Markdown语法'),
            actions(name='cmd',
                    buttons=['发送', '多行输入', {
                        'label': '退出',
                        'type': 'cancel'
                    }])
        ],
                           validate=lambda d: ('msg', '消息不为空')
                           if d['cmd'] == '发送' and not d['msg'] else None)
        if data is None:
            break
        if data['cmd'] == '多行输入':
            data['msg'] = '\n' + textarea('消息内容', help_text='消息内容支持Markdown语法')
        msg_box.append(
            put_markdown('`%s`: %s' % (nickname, data['msg']), sanitize=True))
        chat_msgs.append((nickname, data['msg']))

    refresh_task.close()
    toast("你已经退出聊天室")
Пример #10
0
async def main():
    global chat_msgs

    set_env(title="PyWebIO Chat Room")

    put_markdown(
        "##PyWebIO聊天室\n欢迎来到聊天室,你可以和当前所有在线的人聊天。你可以在浏览器的多个标签页中打开本页面来测试聊天效果。"
        "本应用使用不到80行代码实现,源代码[链接](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)",
        lstrip=True)

    msg_box = output()
    with use_scope('msg-container'):
        style(put_scrollable(msg_box, max_height=300), 'height:300px')
    nickname = await input("请输入你的昵称",
                           required=True,
                           validate=lambda n: '昵称已被使用'
                           if n in online_users or n == '📢' else None)

    online_users.add(nickname)
    chat_msgs.append(
        ('📢', '`%s`加入聊天室. 当前在线人数 %s' % (nickname, len(online_users))))
    msg_box.append(
        put_markdown('`📢`: `%s`加入聊天室. 当前在线人数 %s' %
                     (nickname, len(online_users))))

    @defer_call
    def on_close():
        online_users.remove(nickname)
        chat_msgs.append(
            ('📢', '`%s`退出聊天室. 当前在线人数 %s' % (nickname, len(online_users))))

    refresh_task = run_async(refresh_msg(nickname, msg_box))

    while True:
        data = await input_group('发送消息', [
            input(name='msg', help_text='消息内容支持Markdown 语法', required=True),
            actions(name='cmd',
                    buttons=['发送', {
                        'label': '退出',
                        'type': 'cancel'
                    }])
        ])
        if data is None:
            break

        msg_box.append(put_markdown('`%s`: %s' % (nickname, data['msg'])))
        run_js(
            '$("#pywebio-scope-msg-container>div").animate({ scrollTop: $("#pywebio-scope-msg-container>div").prop("scrollHeight")}, 1000)'
        )  # hack: to scroll bottom
        chat_msgs.append((nickname, data['msg']))

    refresh_task.close()
    toast("你已经退出聊天室")
Пример #11
0
def set_language(s: str, refresh=False):
    global LANG
    for i, lang in enumerate(LANGUAGES):
        # pywebio.session.info.user_language return `zh-CN` or `zh-cn`, depends on browser
        if lang.lower() == s.lower():
            LANG = LANGUAGES[i]
            break
    else:
        LANG = 'en-US'

    WebuiConfig().Language = LANG

    if refresh:
        from pywebio.session import run_js
        run_js('location.reload();')
Пример #12
0
async def refresh_msg(my_name, msg_box):
    """刷新聊天消息"""
    global chat_msgs
    last_idx = len(chat_msgs)
    while True:
        await asyncio.sleep(0.5)
        for m in chat_msgs[last_idx:]:
            if m[0] != my_name:  # 仅刷新其他人的新信息
                msg_box.append(put_markdown('`%s`: %s' % m))
                run_js(
                    '$("#pywebio-scope-msg-container>div").animate({ scrollTop: $("#pywebio-scope-msg-container>div").prop("scrollHeight")}, 1000)'
                )  # hack: to scroll bottom

        # 清理聊天记录
        if len(chat_msgs) > MAX_MESSAGES_CNT:
            chat_msgs = chat_msgs[len(chat_msgs) // 2:]

        last_idx = len(chat_msgs)
Пример #13
0
 def set_navigator(self, group):
     js = f'''
         $("#pywebio-scope-groups").scrollTop(
             $("#pywebio-scope-group_{group[0]}").position().top
             + $("#pywebio-scope-groups").scrollTop() - 59
         )
     '''
     put_button(label=t(f"{group[0]}._info.name"),
                onclick=lambda: run_js(js),
                color='navigator')
Пример #14
0
async def main():
    global chat_msgs

    put_markdown("## 🧊 Добро пожаловать в онлайн чат!")

    msg_box = output()
    put_scrollable(msg_box, height=300, keep_bottom=True)

    nickname = await input("Войти в чат",
                           required=True,
                           placeholder="Ваше имя",
                           validate=lambda n: "Такой ник уже используется!"
                           if n in online_users or n == '📢' else None)
    online_users.add(nickname)

    chat_msgs.append(('📢', f'`{nickname}` присоединился к чату!'))
    msg_box.append(put_markdown(f'📢 `{nickname}` присоединился к чату'))

    refresh_task = run_async(refresh_msg(nickname, msg_box))

    while True:
        data = await input_group(
            "💭 Новое сообщение", [
                input(placeholder="Текст сообщения ...", name="msg"),
                actions(name="cmd",
                        buttons=[
                            "Отправить", {
                                'label': "Выйти из чата",
                                'type': 'cancel'
                            }
                        ])
            ],
            validate=lambda m: ('msg', "Введите текст сообщения!")
            if m["cmd"] == "Отправить" and not m['msg'] else None)

        if data is None:
            break

        msg_box.append(put_markdown(f"`{nickname}`: {data['msg']}"))
        chat_msgs.append((nickname, data['msg']))

    refresh_task.close()

    online_users.remove(nickname)
    toast("Вы вышли из чата!")
    msg_box.append(put_markdown(f'📢 Пользователь `{nickname}` покинул чат!'))
    chat_msgs.append(('📢', f'Пользователь `{nickname}` покинул чат!'))

    put_buttons(['Перезайти'],
                onclick=lambda btn: run_js('window.location.reload()'))
Пример #15
0
async def main():
    global chat_msgs
    put_markdown("Добро пожаловать в онлайн чат\n"
                 "Чат напсиан на языке Python\n"
                 "`Copyright © Mamikon Papikyan`")
    msg_box = output()
    put_scrollable(msg_box, height=300, keep_bottom=True)
    nickname = await input("Войти в чат", required=True,
                           placeholder="Ваше имя",
                           validate=lambda n: "Такой ник уже используется"
                           if n in online_users else None)
    online_users.add(nickname)
    chat_msgs.append(("🔉", f"`{nickname}` присоединился к чату!"))
    msg_box.append(put_markdown(f"`{nickname}` присоединился к чату!"))
    refresh_task = run_async(refresh_msg(nickname, msg_box))
    while True:
        data = await input_group("Новое сообщение", [
            input(placeholder="Текст сообщения", name="msg"),
            actions(name="cmd",
                    buttons=["Отправить", {"label": "Выйти из чата",
                                           "type": "cancel"}]
                    )
        ],
            validate=lambda m: ("msg", "Введите текст сообщения")
            if "Отправить" == m["cmd"] and not m["msg"] else None
        )
        if data is None:
            break
        msg_box.append(put_markdown(f"`{nickname}`: {data['msg']}"))
        chat_msgs.append((nickname, data['msg']))
    # exit chat
    refresh_task.close()
    online_users.remove(nickname)
    toast("Вы вышли из чата")
    msg_box.append(put_markdown(f"🔉 Пользователь {nickname} покинул чат"))
    chat_msgs.append(("🔉", f"Пользователь {nickname} покинул чат"))
    put_buttons(["Перезайти"], onclick=lambda btn: run_js(
                "window.location.reload()"))
Пример #16
0
 def reset(self) -> None:
     run_js(r"""$("\#{dom_id}>code").empty();""".format(dom_id=self.id))
Пример #17
0
 def scroll(self) -> None:
     run_js(
         r"""$("\#{dom_id}").animate({{scrollTop: $("\#{dom_id}").prop("scrollHeight")}}, 0);
     """.format(dom_id=self.id))
Пример #18
0
 def scroll(self) -> None:
     run_js(
         """$("#pywebio-scope-{scope}").scrollTop($("#pywebio-scope-{scope}").prop("scrollHeight"));
     """.format(scope=self.scope))
Пример #19
0
 def reset(self):
     run_js(f"""$("#pywebio-scope-{self.scope}>div").empty();""")
Пример #20
0
def set_localstorage(key, value):
    return run_js("localStorage.setItem(key, value)", key=key, value=value)
Пример #21
0
def add_css(filepath):
    with open(filepath, "r") as f:
        css = f.read().replace("\n", "")
        run_js(f"""$('head').append('<style>{css}</style>')""")
Пример #22
0
 def set_theme(t):
     self.set_theme(t)
     run_js("location.reload()")
Пример #23
0
    def run(self) -> None:
        # setup gui
        set_env(title="Alas", output_animation=False)
        add_css(filepath_css('alas'))
        if self.is_mobile:
            add_css(filepath_css('alas-mobile'))
        else:
            add_css(filepath_css('alas-pc'))

        if self.theme == 'dark':
            add_css(filepath_css('dark-alas'))
        else:
            add_css(filepath_css('light-alas'))

        # Auto refresh when lost connection
        # [For develop] Disable by run `reload=0` in console
        run_js('''
        reload = 1;
        WebIO._state.CurrentSession.on_session_close(
            ()=>{
                setTimeout(
                    ()=>{
                        if (reload == 1){
                            location.reload();
                        }
                    }, 4000
                )
            }
        );
        ''')

        aside = get_localstorage('aside')
        self.show()

        # detect config change
        _thread_wait_config_change = Thread(
            target=self._alas_thread_wait_config_change)
        register_thread(_thread_wait_config_change)
        _thread_wait_config_change.start()

        # save config
        _thread_save_config = Thread(target=self._alas_thread_update_config)
        register_thread(_thread_save_config)
        _thread_save_config.start()

        visibility_state_switch = Switch(status={
            True: [
                lambda: self.__setattr__('visible', True),
                lambda: self.alas_update_overiew_task()
                if self.page == 'Overview' else 0,
                lambda: self.task_handler._task.__setattr__('delay', 15)
            ],
            False: [
                lambda: self.__setattr__('visible', False),
                lambda: self.task_handler._task.__setattr__('delay', 1)
            ]
        },
                                         get_state=get_window_visibility_state,
                                         name='visibility_state')

        self.state_switch = Switch(
            status=self.set_status,
            get_state=lambda: getattr(getattr(self, 'alas', -1), 'state', 0),
            name='state')

        def goto_update():
            self.ui_develop()
            self.dev_update()

        update_switch = Switch(status={
            1:
            lambda: toast(t("Gui.Toast.ClickToUpdate"),
                          duration=0,
                          position='right',
                          color='success',
                          onclick=goto_update)
        },
                               get_state=lambda: updater.state,
                               name='update_state')

        self.task_handler.add(self.state_switch.g(), 2)
        self.task_handler.add(visibility_state_switch.g(), 15)
        self.task_handler.add(update_switch.g(), 1)
        self.task_handler.start()

        # Return to previous page
        if aside not in ["Develop", "Home", None]:
            self.ui_alas(aside)
Пример #24
0
def translate():
    """
        Translate Alas
    """
    set_env(output_animation=False)
    run_js(r"""$('head').append('<style>footer {display: none}</style>')""")

    put_markdown("""
        # Translate
        You can submit(Next) by press `Enter`.
    """)

    dict_lang = {
        "zh-CN": read_file(filepath_i18n('zh-CN')),
        "zh-TW": read_file(filepath_i18n('zh-TW')),
        "en-US": read_file(filepath_i18n('en-US')),
        "ja-JP": read_file(filepath_i18n('ja-JP')),
    }
    modified = {
        "zh-CN": {},
        "zh-TW": {},
        "en-US": {},
        "ja-JP": {},
    }

    list_path = []  # Menu.Task.name
    list_group = []  # Menu
    list_arg = []  # Task
    list_key = []  # name
    for L, _ in deep_iter(dict_lang['zh-CN'], depth=3):
        list_path.append('.'.join(L))
        list_group.append(L[0])
        list_arg.append(L[1])
        list_key.append(L[2])
    total = len(list_path)

    class V:
        lang = lang.LANG
        untranslated_only = False
        clear = False

        idx = -1
        group = ''
        group_idx = 0
        groups = list(dict_lang['zh-CN'].keys())
        arg = ''
        arg_idx = 0
        args = []
        key = ''
        key_idx = 0
        keys = []

    def update_var(group=None, arg=None, key=None):
        if group:
            V.group = group
            V.idx = list_group.index(group)
            V.group_idx = V.idx
            V.arg = list_arg[V.idx]
            V.arg_idx = V.idx
            V.args = list(dict_lang["zh-CN"][V.group].keys())
            V.key = list_key[V.idx]
            V.key_idx = V.idx
            V.keys = list(dict_lang["zh-CN"][V.group][V.arg].keys())
        elif arg:
            V.arg = arg
            V.idx = list_arg.index(arg, V.group_idx)
            V.arg_idx = V.idx
            V.args = list(dict_lang["zh-CN"][V.group].keys())
            V.key = list_key[V.idx]
            V.key_idx = V.idx
            V.keys = list(dict_lang["zh-CN"][V.group][V.arg].keys())
        elif key:
            V.key = key
            V.idx = list_key.index(key, V.arg_idx)
            V.key_idx = V.idx
            V.keys = list(dict_lang["zh-CN"][V.group][V.arg].keys())

        update_form()

    def next_key():
        if V.idx + 1 > total:
            V.idx = -1

        V.idx += 1

        if V.untranslated_only:
            while True:
                # print(V.idx)
                key = deep_get(dict_lang[V.lang], list_path[V.idx])
                if list_path[V.idx] == key or list_path[V.idx].split(
                        '.')[2] == key:
                    break
                else:
                    V.idx += 1
                if V.idx + 1 > total:
                    V.idx = 0
                    break

        (V.group, V.arg, V.key) = tuple(list_path[V.idx].split('.'))
        V.group_idx = list_group.index(V.group)
        V.arg_idx = list_arg.index(V.arg, V.group_idx)
        V.args = list(dict_lang["zh-CN"][V.group].keys())
        V.key_idx = list_key.index(V.key, V.arg_idx)
        V.keys = list(dict_lang["zh-CN"][V.group][V.arg].keys())

    def update_form():
        input_update('arg', options=V.args, value=V.arg)
        input_update('key', options=V.keys, value=V.key)
        for L in LANGUAGES:
            input_update(L,
                         value=deep_get(dict_lang[L],
                                        f'{V.group}.{V.arg}.{V.key}',
                                        'Key not found!'))

        old = deep_get(dict_lang[V.lang], f'{V.group}.{V.arg}.{V.key}',
                       'Key not found!')
        input_update(
            V.lang,
            value=None if V.clear else old,
            help_text=f'{V.group}.{V.arg}.{V.key}',
            placeholder=old,
        )

    def get_inputs():
        out = []
        old = deep_get(dict_lang[V.lang], f'{V.group}.{V.arg}.{V.key}',
                       'Key not found!')
        out.append(
            input(
                name=V.lang,
                label=V.lang,
                value=None if V.clear else old,
                help_text=f'{V.group}.{V.arg}.{V.key}',
                placeholder=old,
            ))
        out.append(
            select(name='group',
                   label='Group',
                   options=V.groups,
                   value=V.group,
                   onchange=lambda g: update_var(group=g),
                   required=True))
        out.append(
            select(name='arg',
                   label='Arg',
                   options=V.args,
                   value=V.arg,
                   onchange=lambda a: update_var(arg=a),
                   required=True))
        out.append(
            select(name='key',
                   label='Key',
                   options=V.keys,
                   value=V.key,
                   onchange=lambda k: update_var(key=k),
                   required=True))
        _LANGUAGES = LANGUAGES.copy()
        _LANGUAGES.remove(V.lang)
        for L in _LANGUAGES:
            out.append(
                input(name=L,
                      label=L,
                      readonly=True,
                      value=deep_get(dict_lang[L],
                                     f'{V.group}.{V.arg}.{V.key}',
                                     'Key not found!')))
        out.append(
            actions(name='action',
                    buttons=[
                        {
                            "label": "Next",
                            "value": 'Next',
                            "type": "submit",
                            "color": "success"
                        },
                        {
                            "label": "Next without save",
                            "value": 'Skip',
                            "type": "submit",
                            "color": "secondary"
                        },
                        {
                            "label": "Submit",
                            "value": "Submit",
                            "type": "submit",
                            "color": "primary"
                        },
                        {
                            "label": "Quit and save",
                            "type": "cancel",
                            "color": "secondary"
                        },
                    ]))

        return out

    def save():
        for LANG in LANGUAGES:
            d = read_file(filepath_i18n(LANG))
            for k in modified[LANG].keys():
                deep_set(d, k, modified[LANG][k])
            write_file(filepath_i18n(LANG), d)

    defer_call(save)

    def loop():
        while True:
            data = input_group(inputs=get_inputs())
            if data is None:
                save()
                break

            if data['action'] == 'Next':

                modified[V.lang][f'{V.group}.{V.arg}.{V.key}'] = data[
                    V.lang].replace("\\n", "\n")
                deep_set(dict_lang[V.lang], f'{V.group}.{V.arg}.{V.key}',
                         data[V.lang].replace("\\n", "\n"))
                next_key()
            if data['action'] == 'Skip':
                next_key()
            elif data['action'] == 'Submit':

                modified[V.lang][f'{V.group}.{V.arg}.{V.key}'] = data[
                    V.lang].replace("\\n", "\n")
                deep_set(dict_lang[V.lang], f'{V.group}.{V.arg}.{V.key}',
                         data[V.lang].replace("\\n", "\n"))
                continue

    def setting():
        data = input_group(inputs=[
            select(name='language',
                   label='Language',
                   options=LANGUAGES,
                   value=V.lang,
                   required=True),
            checkbox(
                name='check',
                label='Other settings',
                options=[{
                    "label": 'Button [Next] only shows untranslated key',
                    'value': 'untranslated',
                    'selected': V.untranslated_only
                }, {
                    "label":
                    'Do not fill input with old value (only effect the language you selected)',
                    "value": "clear",
                    "selected": V.clear
                }])
        ])
        V.lang = data['language']
        V.untranslated_only = True if 'untranslated' in data['check'] else False
        V.clear = True if 'clear' in data['check'] else False

    put_buttons([{
        "label": "Start",
        "value": "start"
    }, {
        "label": "Setting",
        "value": "setting"
    }],
                onclick=[loop, setting])
    next_key()
    setting()
    hold()