From 570476d4f2f7822233c22bc8f49cc061d0c64d35 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Tue, 18 Sep 2018 12:17:13 +0800 Subject: [PATCH 01/16] add count_vowel plalindrome reverse_string --- .gitignore | 4 ++ text-operation/count_vowel.py | 22 ++++++++++ text-operation/plalindrome.py | 73 ++++++++++++++++++++++++++++++++ text-operation/reverse_string.py | 37 ++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 .gitignore create mode 100644 text-operation/count_vowel.py create mode 100644 text-operation/plalindrome.py create mode 100644 text-operation/reverse_string.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28c8676 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.py[cod] +.pytest_cache/ +.mypy_cache/ diff --git a/text-operation/count_vowel.py b/text-operation/count_vowel.py new file mode 100644 index 0000000..2585fd7 --- /dev/null +++ b/text-operation/count_vowel.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + text-operation.count_vowel + -------------------------- + + 统计元音字母——输入一个字符串,统计处其中元音字母的数量。更复杂点的话统计出每个元音字母的数量。 + :copyright: (c) 2018-09-15 by buglan +""" +keys = {'a': 0, 'e': 0, 'i': 0, 'o': 0, 'u': 0} + + +def count_vowel(string: str) -> dict: + for s in string: + if s in keys: + keys[s] += 1 + return keys + + +def test_count_vowel(): + string = 'aeiiousdfsdfsdf' + assert count_vowel(string) == {'a': 1, 'e': 1, 'i': 2, 'o': 1, 'u': 1} diff --git a/text-operation/plalindrome.py b/text-operation/plalindrome.py new file mode 100644 index 0000000..1f31191 --- /dev/null +++ b/text-operation/plalindrome.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + text-operation.plalindrome + -------------------------- + + 判断是否为回文——判断用户输入的字符串是否为回文。回文是指正反拼写形式都是一样的词,譬如“racecar” + :copyright: (c) 2018-09-15 by buglan +""" +from typing import List, Optional, Any + + +class FullError(Exception): + pass + + +class EmptyError(Exception): + pass + + +class Stack: + def __init__(self, maxcount: Optional[int] = None) -> None: + self.items: List = [] + self.maxcount = maxcount + if self.maxcount is not None and self.maxcount <= 0: + raise Exception("self.maxcount cann't <= 0") + + def __len__(self) -> int: + return len(self.items) + + def push(self, value: Any) -> None: + if self.maxcount is not None and len(self) >= self.maxcount: + raise FullError(f"len(self) >= {self.maxcount}") + self.items.append(value) + + def pop(self) -> Any: + if len(self) <= 0: + raise EmptyError("len(self) <= 0") + return self.items.pop() + + def is_empty(self) -> bool: + return len(self.items) == 0 + + def peak(self) -> Any: + if len(self) <= 0: + raise EmptyError("len(self) <= 0") + return self.items[-1] + + +def is_plalindrome(string: str) -> bool: + length: int = len(string) + stack: 'Stack' = Stack(length // 2) + for i in range(length // 2): + stack.push(string[i]) + s: str = "" + for i in range(length // 2): + s += stack.pop() + if len(string) // 2 == 0 and s == string[length // 2:]: + return True + elif s == string[length // 2 + 1:]: + return True + return False + + +def test_is_plalindrome(): + string = 'racecar' + assert is_plalindrome(string) + string = '妈妈爱我,我爱妈妈' + assert is_plalindrome(string) + string = 'aabb' + assert not is_plalindrome(string) + string = 'abba' + assert not is_plalindrome(string) diff --git a/text-operation/reverse_string.py b/text-operation/reverse_string.py new file mode 100644 index 0000000..1409773 --- /dev/null +++ b/text-operation/reverse_string.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + text-operation.reverse_string + ----------------------------- + + 反转字符串 + :copyright: (c) 2018-09-13 by buglan +""" +from typing import List + + +def reverse_string(string: str) -> str: + return string[::-1] + + +def reverse_string2(string: str) -> str: + """ + string is unmut type + so cann't use string[i] = ... + """ + length: int = len(string) + strings: List[str] = list(string) + for i in range(length // 2): + strings[i], strings[length - i - 1] = strings[length - i - + 1], strings[i] + return "".join(strings) + + +def test_reverse_string(): + string = "abcde" + assert "edcba" == reverse_string(string) + + +def test_reverse_string2(): + string = "abcde" + assert "edcba" == reverse_string2(string) From a5681d98327f6dd56037a4fef1cbdb685e2a7d54 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Wed, 26 Sep 2018 12:25:16 +0800 Subject: [PATCH 02/16] editot init commit --- text-operation/editor/qt_editor.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 text-operation/editor/qt_editor.py diff --git a/text-operation/editor/qt_editor.py b/text-operation/editor/qt_editor.py new file mode 100644 index 0000000..8617c66 --- /dev/null +++ b/text-operation/editor/qt_editor.py @@ -0,0 +1,28 @@ +import sys + +from PyQt5.QtWidgets import QApplication, QMainWindow, QAction + + +class Editor(QMainWindow): + def __init__(self): + super().__init__() + self.init_ui() + + def init_ui(self): + menubar = self.menuBar() + fileMenu = menubar.addMenu('File') + newAct = QAction('New', self) + settingAct = QAction('Setting', self) + exitAct = QAction('Exit', self) + fileMenu.addAction(newAct) + fileMenu.addAction(settingAct) + fileMenu.addAction(exitAct) + self.setGeometry(500, 300, 800, 600) + self.setWindowTitle('文本编辑器0.0.1') + self.show() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + editor = Editor() + sys.exit(app.exec_()) From a821bfb445096e32bca8b6cec41adfe952181fb3 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Wed, 26 Sep 2018 19:03:40 +0800 Subject: [PATCH 03/16] add more function on editor --- text-operation/editor/Makefile | 2 + text-operation/editor/qt_editor.py | 104 +++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 text-operation/editor/Makefile diff --git a/text-operation/editor/Makefile b/text-operation/editor/Makefile new file mode 100644 index 0000000..22288c1 --- /dev/null +++ b/text-operation/editor/Makefile @@ -0,0 +1,2 @@ +run: + python qt_editor.py diff --git a/text-operation/editor/qt_editor.py b/text-operation/editor/qt_editor.py index 8617c66..6681b2a 100644 --- a/text-operation/editor/qt_editor.py +++ b/text-operation/editor/qt_editor.py @@ -1,26 +1,120 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + editor.qt_editor + ---------------- + + text editor + hope it do more + :copyright: (c) 2018-09-26 by buglan +""" + import sys +from pathlib import Path -from PyQt5.QtWidgets import QApplication, QMainWindow, QAction +from PyQt5.QtGui import QFont +from PyQt5.QtWidgets import (QAction, QApplication, QFileDialog, QFontDialog, + QMainWindow, QMenu, QTextEdit, qApp) class Editor(QMainWindow): + def __init__(self): super().__init__() + self.font = QFont("Monaco", 14) + self.font.setFixedPitch(True) + self.title = 'simple text editor' + self.textEditor = QTextEdit() + self.textEditor.setFont(self.font) + self.menubar = self.menuBar() + self.menubar.setFont(self.font) self.init_ui() - def init_ui(self): - menubar = self.menuBar() - fileMenu = menubar.addMenu('File') + def setFileMenu(self): + # fileMenu setting + fileMenu = self.menubar.addMenu('File') + fileMenu.setFont(self.font) + + # action newAct = QAction('New', self) + openAct = QAction('Open', self) + autoSave = QAction('AutoSavle', self, checkable=True) settingAct = QAction('Setting', self) exitAct = QAction('Exit', self) + + # action detail + openAct.triggered.connect(self.showFileDialog) + + # autoSave set default False + autoSave.setChecked(False) + + # add action on fileMenu fileMenu.addAction(newAct) + fileMenu.addAction(openAct) + fileMenu.addAction(autoSave) fileMenu.addAction(settingAct) fileMenu.addAction(exitAct) + + def setSettingMenu(self): + # settingMenu setting + settingMenu = self.menubar.addMenu('Setting') + settingMenu.setFont(self.font) + + # action + fontAct = QAction('Font', self) + + # action detail + settingMenu.addAction(fontAct) + + # add action on settingMenu + fontAct.triggered.connect(self.showFontDialog) + + def showFontDialog(self): + font, ok = QFontDialog.getFont() + + if ok: + # QApplication.setFont(font) + print(self.textEditor.font) + self.font = font + print("Display Fonts: ", font) + + def init_ui(self): + self.setFileMenu() + self.setSettingMenu() + self.setCentralWidget(self.textEditor) + + # setting window self.setGeometry(500, 300, 800, 600) - self.setWindowTitle('文本编辑器0.0.1') + self.setWindowTitle(self.title) self.show() + def contextMenuEvent(self, event): + cmenu = QMenu(self) + + newAct = cmenu.addAction("New") + openAct = cmenu.addAction("Open") + quitAct = cmenu.addAction("Quit") + action = cmenu.exec_(self.mapToGlobal(event.pos())) + + if action == newAct: + pass + + if action == quitAct: + qApp.quit() + + if action == openAct: + pass + + def showFileDialog(self): + # get current use main home full path as string + main_home = Path.home().absolute().as_posix() + fname = QFileDialog.getOpenFileName(self, 'Open File', main_home) + if fname[0]: + f = open(fname[0], 'r') + with f: + content = f.read() + self.textEditor.setText(content) + if __name__ == "__main__": app = QApplication(sys.argv) From 9d279437a45d93eb5a43004a37d34a3f369d54c6 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Fri, 28 Sep 2018 20:48:22 +0800 Subject: [PATCH 04/16] finish basic text editor --- text-operation/editor/qt_editor.py | 58 +++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/text-operation/editor/qt_editor.py b/text-operation/editor/qt_editor.py index 6681b2a..aa13d17 100644 --- a/text-operation/editor/qt_editor.py +++ b/text-operation/editor/qt_editor.py @@ -12,20 +12,24 @@ import sys from pathlib import Path -from PyQt5.QtGui import QFont +from PyQt5.QtGui import QFont, QFontMetricsF from PyQt5.QtWidgets import (QAction, QApplication, QFileDialog, QFontDialog, - QMainWindow, QMenu, QTextEdit, qApp) + QMainWindow, QMenu, qApp, + QPlainTextEdit) class Editor(QMainWindow): - def __init__(self): super().__init__() + self.currentpath = '' self.font = QFont("Monaco", 14) self.font.setFixedPitch(True) self.title = 'simple text editor' - self.textEditor = QTextEdit() + self.textEditor = QPlainTextEdit() self.textEditor.setFont(self.font) + self.textEditor.setTabStopDistance( + QFontMetricsF(self.textEditor.font()).width(' ') * 4) + # set tab length 4 spaces self.menubar = self.menuBar() self.menubar.setFont(self.font) self.init_ui() @@ -39,11 +43,19 @@ def setFileMenu(self): newAct = QAction('New', self) openAct = QAction('Open', self) autoSave = QAction('AutoSavle', self, checkable=True) - settingAct = QAction('Setting', self) exitAct = QAction('Exit', self) + saveAct = QAction('Save', self) + exitAct.triggered.connect(qApp.quit) + + newAct.setShortcut('Ctrl+N') + openAct.setShortcut('Ctrl+O') + exitAct.setShortcut('Ctrl+Q') + saveAct.setShortcut('Ctrl+S') # action detail - openAct.triggered.connect(self.showFileDialog) + openAct.triggered.connect(self.openFile) + newAct.triggered.connect(self.newFile) + saveAct.triggered.connect(self.saveFile) # autoSave set default False autoSave.setChecked(False) @@ -51,10 +63,25 @@ def setFileMenu(self): # add action on fileMenu fileMenu.addAction(newAct) fileMenu.addAction(openAct) + fileMenu.addAction(saveAct) fileMenu.addAction(autoSave) - fileMenu.addAction(settingAct) fileMenu.addAction(exitAct) + def newFile(self): + fname = QFileDialog.getSaveFileName(self, 'Save file') + context = self.textEditor.toPlainText() + if fname[0]: + with open(fname[0], 'w') as f: + f.write(context) + self.currentpath = fname[0] + + def saveFile(self): + path = self.currentpath + context = self.textEditor.toPlainText() + if path: + with open(path, 'w') as f: + f.write(context) + def setSettingMenu(self): # settingMenu setting settingMenu = self.menubar.addMenu('Setting') @@ -67,16 +94,13 @@ def setSettingMenu(self): settingMenu.addAction(fontAct) # add action on settingMenu - fontAct.triggered.connect(self.showFontDialog) + fontAct.triggered.connect(self.selectFont) - def showFontDialog(self): + def selectFont(self): font, ok = QFontDialog.getFont() if ok: - # QApplication.setFont(font) - print(self.textEditor.font) - self.font = font - print("Display Fonts: ", font) + self.textEditor.setFont(font) def init_ui(self): self.setFileMenu() @@ -105,15 +129,15 @@ def contextMenuEvent(self, event): if action == openAct: pass - def showFileDialog(self): + def openFile(self): # get current use main home full path as string main_home = Path.home().absolute().as_posix() fname = QFileDialog.getOpenFileName(self, 'Open File', main_home) if fname[0]: - f = open(fname[0], 'r') - with f: + with open(fname[0], 'r') as f: content = f.read() - self.textEditor.setText(content) + self.textEditor.setPlainText(content) + self.currentpath = fname[0] if __name__ == "__main__": From ac532dc274ff7b8134de2001c2c08fab71ccba21 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Tue, 9 Oct 2018 11:55:27 +0800 Subject: [PATCH 05/16] update --- README.md | 8 ++-- text-operation/diary/Pipfile | 12 +++++ text-operation/diary/Pipfile.lock | 63 ++++++++++++++++++++++++++ text-operation/diary/config.py | 14 ++++++ text-operation/diary/diary/__init__.py | 19 ++++++++ text-operation/diary/wsgi.py | 6 +++ text-operation/editor/qt_editor.py | 6 +-- text-operation/editor/readme.md | 36 +++++++++++++++ text-operation/rss/templates/rss.html | 11 +++++ text-operation/rss/tests/test_basic.py | 0 text-operation/rss/wsgi.py | 17 +++++++ 11 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 text-operation/diary/Pipfile create mode 100644 text-operation/diary/Pipfile.lock create mode 100644 text-operation/diary/config.py create mode 100644 text-operation/diary/diary/__init__.py create mode 100644 text-operation/diary/wsgi.py create mode 100644 text-operation/editor/readme.md create mode 100644 text-operation/rss/templates/rss.html create mode 100644 text-operation/rss/tests/test_basic.py create mode 100644 text-operation/rss/wsgi.py diff --git a/README.md b/README.md index f452a21..6a5aa1c 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ ### 文本操作 -* 逆转字符串——输入一个字符串,将其逆转并输出。 +* ~~逆转字符串——输入一个字符串,将其逆转并输出。~~ * 拉丁猪文字游戏——这是一个英语语言游戏。基本规则是将一个英语单词的第一个辅音音素的字母移动到词尾并且加上后缀-ay(譬如“banana”会变成“anana-bay”)。可以在维基百科上了解更多内容。 -* 统计元音字母——输入一个字符串,统计处其中元音字母的数量。更复杂点的话统计出每个元音字母的数量。 -* 判断是否为回文——判断用户输入的字符串是否为回文。回文是指正反拼写形式都是一样的词,譬如“racecar”。 +* ~~统计元音字母——输入一个字符串,统计处其中元音字母的数量。更复杂点的话统计出每个元音字母的数量。~~ +* ~~判断是否为回文——判断用户输入的字符串是否为回文。回文是指正反拼写形式都是一样的词,譬如“racecar”。~~ * 统计字符串中的单词数目——统计字符串中单词的数目,更复杂的话从一个文本中读出字符串并生成单词数目统计结果。 * 文本编辑器——记事本类型的应用,可以打开、编辑、保存文本文档。可以增加单词高亮和其它的一些特性。 * RSS源创建器——可以从其它来源读取文本并将其以RSS或者Atom的格式发布出去。 @@ -61,6 +61,7 @@ ### Web应用 +* todo list, 可以管理todo清单, 并设定短信发送时间, 在指定时间发送短信. * 所见即所得编辑器——创建一个在线编辑器,允许用户移动元素、创建表格、书写文本、设置颜色,而用户不必懂HTML。就像Dreamweaver或者FrontPage。如果需要例子的话,可以参看DIC。 * 分页浏览器——创建一个可以分页的小型网页浏览器,可以同时浏览几个网页。简化一点的话不要考虑Javascript或者其它客户端代码。 * 文件下载器——该程序可以从网页上下载各种资源,包括视频和其它文件。用于有很多下载链接的网页。 @@ -136,4 +137,3 @@ * 刽子手——从文件中随机选择一个单词,让玩家猜单词中的字母。旁边是一幅隐藏的行绞刑的画,猜错一个单词,画就显示出一部分。画全部显示出来时还没能猜全的话玩家就输了。 * 填字游戏——创建一个填字游戏,并为每个词提供一个提示信息,让玩家填上所有正确的单词。 * 青蛙跳——让青蛙跳过河或者马路,过河的话要跳在顺流而下速度各异的木头或者睡莲叶子上,过马路的话要避开速度各异的车子。 - diff --git a/text-operation/diary/Pipfile b/text-operation/diary/Pipfile new file mode 100644 index 0000000..ab56e8a --- /dev/null +++ b/text-operation/diary/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "*" + +[dev-packages] + +[requires] +python_version = "3.7" diff --git a/text-operation/diary/Pipfile.lock b/text-operation/diary/Pipfile.lock new file mode 100644 index 0000000..b147ab6 --- /dev/null +++ b/text-operation/diary/Pipfile.lock @@ -0,0 +1,63 @@ +{ + "_meta": { + "hash": { + "sha256": "a82b674d67d29678775ff6b773de1686a9593749ec14483b0d8e05131b662286" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "markers": "python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.1.*'", + "version": "==7.0" + }, + "flask": { + "hashes": [ + "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", + "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + } + }, + "develop": {} +} diff --git a/text-operation/diary/config.py b/text-operation/diary/config.py new file mode 100644 index 0000000..51911c0 --- /dev/null +++ b/text-operation/diary/config.py @@ -0,0 +1,14 @@ +class BaseConfig: + DEBUG = True + + +class TestConfig: + DEBUG = True + TESTING = True + + +class ProConfig: + DEBUG = False + + +config = {'base': BaseConfig, 'pro': ProConfig, 'test': TestConfig} diff --git a/text-operation/diary/diary/__init__.py b/text-operation/diary/diary/__init__.py new file mode 100644 index 0000000..5f5adbb --- /dev/null +++ b/text-operation/diary/diary/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + text-operation.diary + -------------------- + + 访客留言簿/日志——允许人们添加评论或者日记,可以设置开启/关闭评论, + 并且可以记录下每一条目的时间。也可以做成喊话器。 + :copyright: (c) 2018-10-07 by buglan +""" +from flask import Flask +from config import config + +app = Flask(__name__) + + +def create_app(config=config['base']): + app.config.from_object(config) + return app diff --git a/text-operation/diary/wsgi.py b/text-operation/diary/wsgi.py new file mode 100644 index 0000000..c777061 --- /dev/null +++ b/text-operation/diary/wsgi.py @@ -0,0 +1,6 @@ +from diary import create_app + +app = create_app() + +if __name__ == "__main__": + app.run() diff --git a/text-operation/editor/qt_editor.py b/text-operation/editor/qt_editor.py index aa13d17..77110de 100644 --- a/text-operation/editor/qt_editor.py +++ b/text-operation/editor/qt_editor.py @@ -14,11 +14,11 @@ from PyQt5.QtGui import QFont, QFontMetricsF from PyQt5.QtWidgets import (QAction, QApplication, QFileDialog, QFontDialog, - QMainWindow, QMenu, qApp, - QPlainTextEdit) + QMainWindow, QMenu, qApp, QPlainTextEdit) class Editor(QMainWindow): + def __init__(self): super().__init__() self.currentpath = '' @@ -27,9 +27,9 @@ def __init__(self): self.title = 'simple text editor' self.textEditor = QPlainTextEdit() self.textEditor.setFont(self.font) + # set tab length 4 spaces self.textEditor.setTabStopDistance( QFontMetricsF(self.textEditor.font()).width(' ') * 4) - # set tab length 4 spaces self.menubar = self.menuBar() self.menubar.setFont(self.font) self.init_ui() diff --git a/text-operation/editor/readme.md b/text-operation/editor/readme.md new file mode 100644 index 0000000..7047a9b --- /dev/null +++ b/text-operation/editor/readme.md @@ -0,0 +1,36 @@ +## 1. 文件操作 + +- Ctrl+O 打开文件 +- ctrl+N 新建文件 +- Ctrl+S 保存文件   +- ctrl+alt+s 文件另存为 +- Ctrl+shift+s +- 保存所有打开文件   +- alt+F4 退出程序   +- ctrl+tab 文件标签跳转跳至西夏一个打开文件 +- ctrl+w 关闭当前文件 + +## 2. 编辑相关快捷键 + +- Ctrl+c 复制   +- ctrl+x 剪切    +- shift+delete 剪切   +- ctrl+v粘贴   +- ctrl+z 撤销上一次操作 +- ctrl+y 重做,撤销后重做刚刚撤销的动作 +- ctrl+a 全选   +- ctrl+d 复制当前行至下方,或者复制选中区域至其后 +- ctrl+alt+t 与上一行进行交换   +- ctrl+shift+Up 将当前行上移一行   +- ctrl+shift+down 当前行下移一行     +- ctrl+L 删除当前行   +- ctrl+j 合并多行 +- ctrl+G 跳转某行对话框 +- ctrl+q 添加删除注释    +- ctrl+shift+q 区块添加删除注释   +- ctrl+space 触发函数自动完成列表    +- ctrl+shift+space 触发函数参数提示 +- ctrl+f 查找   +- ctrl+h 查找替换对话框     +- ctrl+T 上下行交换 +- ctrl+空格 输入法切换 diff --git a/text-operation/rss/templates/rss.html b/text-operation/rss/templates/rss.html new file mode 100644 index 0000000..239ead5 --- /dev/null +++ b/text-operation/rss/templates/rss.html @@ -0,0 +1,11 @@ + + + + + + rss 源创建器 + + + 请在这里创建你的rss源 + + diff --git a/text-operation/rss/tests/test_basic.py b/text-operation/rss/tests/test_basic.py new file mode 100644 index 0000000..e69de29 diff --git a/text-operation/rss/wsgi.py b/text-operation/rss/wsgi.py new file mode 100644 index 0000000..19e7fe9 --- /dev/null +++ b/text-operation/rss/wsgi.py @@ -0,0 +1,17 @@ +from flask import Flask, render_template + +app = Flask(__name__) + + +@app.route('/') +def index(): + return render_template('rss.html') + + +@app.route('/rss-lists') +def rss_lists(): + return 'rss lists' + + +if __name__ == "__main__": + app.run(debug=True) From c9cf9b2b2a56448964905a6d305741f251be2d2e Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Mon, 22 Oct 2018 22:28:46 +0800 Subject: [PATCH 06/16] add half todo list --- README.md | 2 +- web-application/todo_list/Dockerfile | 0 web-application/todo_list/Pipfile | 13 ++ web-application/todo_list/Pipfile.lock | 79 ++++++++++++ web-application/todo_list/template/base.html | 55 ++++++++ .../todo_list/template/todo/add_todo.html | 14 ++ .../todo_list/template/todo/index.html | 32 +++++ .../todo_list/template/todo/search_todo.html | 14 ++ .../todo_list/template/todo/update_todo.html | 15 +++ web-application/todo_list/todo_web.py | 122 ++++++++++++++++++ 10 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 web-application/todo_list/Dockerfile create mode 100644 web-application/todo_list/Pipfile create mode 100644 web-application/todo_list/Pipfile.lock create mode 100644 web-application/todo_list/template/base.html create mode 100644 web-application/todo_list/template/todo/add_todo.html create mode 100644 web-application/todo_list/template/todo/index.html create mode 100644 web-application/todo_list/template/todo/search_todo.html create mode 100644 web-application/todo_list/template/todo/update_todo.html create mode 100644 web-application/todo_list/todo_web.py diff --git a/README.md b/README.md index 6a5aa1c..e6d745f 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ ### Web应用 -* todo list, 可以管理todo清单, 并设定短信发送时间, 在指定时间发送短信. +* ~~todo list, 可以管理todo清单, 并设定短信发送时间, 在指定时间发送短信.~~(half) * 所见即所得编辑器——创建一个在线编辑器,允许用户移动元素、创建表格、书写文本、设置颜色,而用户不必懂HTML。就像Dreamweaver或者FrontPage。如果需要例子的话,可以参看DIC。 * 分页浏览器——创建一个可以分页的小型网页浏览器,可以同时浏览几个网页。简化一点的话不要考虑Javascript或者其它客户端代码。 * 文件下载器——该程序可以从网页上下载各种资源,包括视频和其它文件。用于有很多下载链接的网页。 diff --git a/web-application/todo_list/Dockerfile b/web-application/todo_list/Dockerfile new file mode 100644 index 0000000..e69de29 diff --git a/web-application/todo_list/Pipfile b/web-application/todo_list/Pipfile new file mode 100644 index 0000000..e2d9eba --- /dev/null +++ b/web-application/todo_list/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "*" +flask-sqlalchemy = "*" + +[dev-packages] + +[requires] +python_version = "3.7" diff --git a/web-application/todo_list/Pipfile.lock b/web-application/todo_list/Pipfile.lock new file mode 100644 index 0000000..0ec232b --- /dev/null +++ b/web-application/todo_list/Pipfile.lock @@ -0,0 +1,79 @@ +{ + "_meta": { + "hash": { + "sha256": "e3c78199a09ad7c09a5b177bfa33693280ac6bb34a02d76daf99e39bdeabc4de" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "markers": "python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.1.*'", + "version": "==7.0" + }, + "flask": { + "hashes": [ + "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", + "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "flask-sqlalchemy": { + "hashes": [ + "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", + "sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53" + ], + "index": "pypi", + "version": "==2.3.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:a7de3201740a857380421ef286166134e10fe58846bcefbc9d6424a69a0b99ec", + "sha256:aca4fc561b7671115a2156f625f2eaa5e0e3527e0adf2870340e7968c0a81f85" + ], + "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", + "version": "==1.0.0" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "sqlalchemy": { + "hashes": [ + "sha256:c5951d9ef1d5404ed04bae5a16b60a0779087378928f997a294d1229c6ca4d3e" + ], + "version": "==1.2.12" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + } + }, + "develop": {} +} diff --git a/web-application/todo_list/template/base.html b/web-application/todo_list/template/base.html new file mode 100644 index 0000000..494919d --- /dev/null +++ b/web-application/todo_list/template/base.html @@ -0,0 +1,55 @@ + + + + + + + {%block title%} {%endblock%} + + + + + + + {%block body%} + {%endblock%} + + + \ No newline at end of file diff --git a/web-application/todo_list/template/todo/add_todo.html b/web-application/todo_list/template/todo/add_todo.html new file mode 100644 index 0000000..0e759e4 --- /dev/null +++ b/web-application/todo_list/template/todo/add_todo.html @@ -0,0 +1,14 @@ +{%extends 'base.html'%} + +{%block title%}新增 | todo 小网站{%endblock%} + +{%block body%} +
+
+
+ + +
+
+
+{%endblock%} diff --git a/web-application/todo_list/template/todo/index.html b/web-application/todo_list/template/todo/index.html new file mode 100644 index 0000000..30117f9 --- /dev/null +++ b/web-application/todo_list/template/todo/index.html @@ -0,0 +1,32 @@ +{%extends 'base.html'%} + +{%block title%}todo 小网站{%endblock%} + +{%block body%} +{% if todos %} +
+
+

now time is: {{ time }}

+

增加 + 搜索

+ + + + + + + {%for todo in todos%} + + + + + + {%endfor%} +
编号标题状态
{{todo.id}}{{todo.title}}{{todo.status}} 切换 删除 + 修改
+ {%else%} +

NO TODO HERE

+ {%endif%} +
+
+{%endblock%} diff --git a/web-application/todo_list/template/todo/search_todo.html b/web-application/todo_list/template/todo/search_todo.html new file mode 100644 index 0000000..d097b65 --- /dev/null +++ b/web-application/todo_list/template/todo/search_todo.html @@ -0,0 +1,14 @@ +{%extends 'base.html'%} + +{%block title%}搜索 | todo 小网站{%endblock%} + +{%block body%} +
+
+
+ + +
+
+
+{%endblock%} diff --git a/web-application/todo_list/template/todo/update_todo.html b/web-application/todo_list/template/todo/update_todo.html new file mode 100644 index 0000000..b8a093a --- /dev/null +++ b/web-application/todo_list/template/todo/update_todo.html @@ -0,0 +1,15 @@ +{%extends 'base.html'%} + +{%block title%}修改 | todo 小网站{%endblock%} + +{%block body%} +
+
+
+ + + +
+
+
+{%endblock%} diff --git a/web-application/todo_list/todo_web.py b/web-application/todo_list/todo_web.py new file mode 100644 index 0000000..3bcf10e --- /dev/null +++ b/web-application/todo_list/todo_web.py @@ -0,0 +1,122 @@ +from datetime import datetime + +from flask import Flask, abort, redirect, render_template, request, url_for +from flask_sqlalchemy import SQLAlchemy + +app = Flask(__name__, template_folder='./template', static_folder='./static') + +# config sqlite config +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db' +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +db = SQLAlchemy(app) + + +class Todo(db.Model): + __tablename__ = 'todo' + id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.String(128), unique=True, nullable=False) + status = db.Column(db.Boolean, default=False) + created_time = db.Column(db.DateTime) + finished_time = db.Column(db.DateTime) + + def __init__(self, title): + self.title = title + self.created_time = datetime.now() + + def __repr__(self): + return f'' + + +@app.before_first_request +def before_first_do(): + """ + create database or do init + """ + try: + db.create_all() + except Exception as e: + print(e) + else: + pass + + +@app.route('/') +def index(): + todos = Todo.query.all() + time = datetime.now() + return render_template('todo/index.html', time=time, todos=todos) + + +@app.route('/add_todo', methods=['GET', 'POST']) +def add_todo(): + if request.method == 'GET': + return render_template('todo/add_todo.html') + elif request.method == 'POST': + title = request.form.get('title') + todo = Todo(title=title) + db.session.add(todo) + db.session.commit() + return redirect(url_for('index')) + else: + # bad request + abort(400) + + +@app.route('/toggle') +def toggle(): + id = request.args.get('id') + todo = Todo.query.get_or_404(id) + todo.status = (not todo.status) + db.session.add(todo) + db.session.commit() + return redirect(url_for('index')) + + +@app.route('/delete_todo') +def delete_todo(): + """ + 删除 todo中的一项 + """ + id = request.args.get('id') + todo = Todo.query.get_or_404(id) + db.session.delete(todo) + db.session.commit() + return redirect(url_for('index')) + + +@app.route('/update_todo', methods=['GET', 'POST']) +def update_todo(): + if request.method == 'GET': + return render_template('todo/update_todo.html') + elif request.method == 'POST': + id = request.form.get('id') + title = request.form.get('title') + todo = Todo.query.get_or_404(id) + todo.title = title + db.session.add(todo) + db.session.commit() + return redirect(url_for('index')) + else: + abort(400) + + +@app.route('/search_todo', methods=['GET', 'POST']) +def search_todo(): + if request.method == 'GET': + return render_template('todo/search_todo.html') + elif request.method == 'POST': + title = request.form.get('title') + todos = Todo.query.filter(Todo.title.like('%' + title + '%')).all() + time = datetime.now() + return render_template('todo/index.html', todos=todos, time=time) + + return "hello world" + + +@app.route('/test') +def test(): + return render_template('todo/test.html') + + +if __name__ == "__main__": + app.run(debug=True) From 2fb22c2fb4904b7531fc60be8382f8c40b2ff15d Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Wed, 24 Oct 2018 23:28:16 +0800 Subject: [PATCH 07/16] 80% todo list task --- README.md | 1 + web-application/todo_list/Dockerfile | 1 + web-application/todo_list/Pipfile | 2 + web-application/todo_list/Pipfile.lock | 64 +++++++++++++++++- web-application/todo_list/gunicorn.config.py | 3 + web-application/todo_list/template/base.html | 60 +++------------- .../todo_list/template/todo/add_todo.html | 15 ++-- .../todo_list/template/todo/index.html | 48 +++++++------ .../todo_list/template/todo/search_todo.html | 15 ++-- .../todo_list/template/todo/update_todo.html | 17 +++-- web-application/todo_list/todo.db | Bin 0 -> 12288 bytes web-application/todo_list/todo_web.py | 1 + 12 files changed, 136 insertions(+), 91 deletions(-) create mode 100644 web-application/todo_list/gunicorn.config.py create mode 100644 web-application/todo_list/todo.db diff --git a/README.md b/README.md index e6d745f..49d4659 100644 --- a/README.md +++ b/README.md @@ -137,3 +137,4 @@ * 刽子手——从文件中随机选择一个单词,让玩家猜单词中的字母。旁边是一幅隐藏的行绞刑的画,猜错一个单词,画就显示出一部分。画全部显示出来时还没能猜全的话玩家就输了。 * 填字游戏——创建一个填字游戏,并为每个词提供一个提示信息,让玩家填上所有正确的单词。 * 青蛙跳——让青蛙跳过河或者马路,过河的话要跳在顺流而下速度各异的木头或者睡莲叶子上,过马路的话要避开速度各异的车子。 +* 飞机大战--模仿雷电2 困难点可以多做几关, 再困难可以设置难易度. diff --git a/web-application/todo_list/Dockerfile b/web-application/todo_list/Dockerfile index e69de29..673ced6 100644 --- a/web-application/todo_list/Dockerfile +++ b/web-application/todo_list/Dockerfile @@ -0,0 +1 @@ +FROM: python:3 diff --git a/web-application/todo_list/Pipfile b/web-application/todo_list/Pipfile index e2d9eba..84821a1 100644 --- a/web-application/todo_list/Pipfile +++ b/web-application/todo_list/Pipfile @@ -6,6 +6,8 @@ name = "pypi" [packages] flask = "*" flask-sqlalchemy = "*" +gevent = "*" +gunicorn = "*" [dev-packages] diff --git a/web-application/todo_list/Pipfile.lock b/web-application/todo_list/Pipfile.lock index 0ec232b..590a9d4 100644 --- a/web-application/todo_list/Pipfile.lock +++ b/web-application/todo_list/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "e3c78199a09ad7c09a5b177bfa33693280ac6bb34a02d76daf99e39bdeabc4de" + "sha256": "1c17f06b505e80646d239b8c3bbd25add0287e3a77ffff19cf3809a808f3ec44" }, "pipfile-spec": 6, "requires": { @@ -40,6 +40,68 @@ "index": "pypi", "version": "==2.3.2" }, + "gevent": { + "hashes": [ + "sha256:1f277c5cf060b30313c5f9b91588f4c645e11839e14a63c83fcf6f24b1bc9b95", + "sha256:298a04a334fb5e3dcd6f89d063866a09155da56041bc94756da59db412cb45b1", + "sha256:30e9b2878d5b57c68a40b3a08d496bcdaefc79893948989bb9b9fab087b3f3c0", + "sha256:33533bc5c6522883e4437e901059fe5afa3ea74287eeea27a130494ff130e731", + "sha256:3f06f4802824c577272960df003a304ce95b3e82eea01dad2637cc8609c80e2c", + "sha256:419fd562e4b94b91b58cccb3bd3f17e1a11f6162fca6c591a7822bc8a68f023d", + "sha256:4ea938f44b882e02cca9583069d38eb5f257cc15a03e918980c307e7739b1038", + "sha256:51143a479965e3e634252a0f4a1ea07e5307cf8dc773ef6bf9dfe6741785fb4c", + "sha256:5bf9bd1dd4951552d9207af3168f420575e3049016b9c10fe0c96760ce3555b7", + "sha256:6004512833707a1877cc1a5aea90fd182f569e089bc9ab22a81d480dad018f1b", + "sha256:640b3b52121ab519e0980cb38b572df0d2bc76941103a697e828c13d76ac8836", + "sha256:6951655cc18b8371d823e81c700883debb0f633aae76f425dfeb240f76b95a67", + "sha256:71eeb8d9146e8131b65c3364bb760b097c21b7b9fdbec91bf120685a510f997a", + "sha256:7c899e5a6f94d6310352716740f05e41eb8c52d995f27fc01e90380913aa8f22", + "sha256:8465f84ba31aaf52a080837e9c5ddd592ab0a21dfda3212239ce1e1796f4d503", + "sha256:99de2e38dde8669dd30a8a1261bdb39caee6bd00a5f928d01dfdb85ab0502562", + "sha256:9fa4284b44bc42bef6e437488d000ae37499ccee0d239013465638504c4565b7", + "sha256:a1beea0443d3404c03e069d4c4d9fc13d8ec001771c77f9a23f01911a41f0e49", + "sha256:a66a26b78d90d7c4e9bf9efb2b2bd0af49234604ac52eaca03ea79ac411e3f6d", + "sha256:a94e197bd9667834f7bb6bd8dff1736fab68619d0f8cd78a9c1cebe3c4944677", + "sha256:ac0331d3a3289a3d16627742be9c8969f293740a31efdedcd9087dadd6b2da57", + "sha256:d26b57c50bf52fb38dadf3df5bbecd2236f49d7ac98f3cf32d6b8a2d25afc27f", + "sha256:fd23b27387d76410eb6a01ea13efc7d8b4b95974ba212c336e8b1d6ab45a9578" + ], + "index": "pypi", + "version": "==1.3.7" + }, + "greenlet": { + "hashes": [ + "sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0", + "sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28", + "sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8", + "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304", + "sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0", + "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214", + "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043", + "sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6", + "sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625", + "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc", + "sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638", + "sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163", + "sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4", + "sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490", + "sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248", + "sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939", + "sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87", + "sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720", + "sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656" + ], + "markers": "platform_python_implementation == 'CPython'", + "version": "==0.4.15" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, "itsdangerous": { "hashes": [ "sha256:a7de3201740a857380421ef286166134e10fe58846bcefbc9d6424a69a0b99ec", diff --git a/web-application/todo_list/gunicorn.config.py b/web-application/todo_list/gunicorn.config.py new file mode 100644 index 0000000..a62b8f2 --- /dev/null +++ b/web-application/todo_list/gunicorn.config.py @@ -0,0 +1,3 @@ +workers = 4 +worker_class = "gevent" +bind = "0.0.0.0:8888" diff --git a/web-application/todo_list/template/base.html b/web-application/todo_list/template/base.html index 494919d..2a7f80d 100644 --- a/web-application/todo_list/template/base.html +++ b/web-application/todo_list/template/base.html @@ -1,55 +1,17 @@ - - - - {%block title%} {%endblock%} + + + + {%block title%} {%endblock%} - - - - - - {%block body%} - {%endblock%} - - - \ No newline at end of file + + {%block body%} + {%endblock%} + + diff --git a/web-application/todo_list/template/todo/add_todo.html b/web-application/todo_list/template/todo/add_todo.html index 0e759e4..27d19f1 100644 --- a/web-application/todo_list/template/todo/add_todo.html +++ b/web-application/todo_list/template/todo/add_todo.html @@ -4,11 +4,14 @@ {%block body%}
-
-
- - -
-
+

Add Todo

+
+
+
+ + +
+ +
{%endblock%} diff --git a/web-application/todo_list/template/todo/index.html b/web-application/todo_list/template/todo/index.html index 30117f9..60779c6 100644 --- a/web-application/todo_list/template/todo/index.html +++ b/web-application/todo_list/template/todo/index.html @@ -3,30 +3,34 @@ {%block title%}todo 小网站{%endblock%} {%block body%} -{% if todos %}
-
-

now time is: {{ time }}

-

增加 - 搜索

- - - - - - - {%for todo in todos%} - - - - - - {%endfor%} +

Todo List

+
+
+
编号标题状态
{{todo.id}}{{todo.title}}{{todo.status}} 切换 删除 - 修改
+ + + + + + + + + + + + {%for todo in todos%} + + + + + + + + + {%endfor%} +
#标题开始时间结束时间当前状态管理
{{todo.id}}{{todo.title}}20182019{{todo.status}}新增 切换 修改 删除 搜索
- {%else%} -

NO TODO HERE

- {%endif%}
{%endblock%} diff --git a/web-application/todo_list/template/todo/search_todo.html b/web-application/todo_list/template/todo/search_todo.html index d097b65..e162c01 100644 --- a/web-application/todo_list/template/todo/search_todo.html +++ b/web-application/todo_list/template/todo/search_todo.html @@ -4,11 +4,14 @@ {%block body%}
-
-
- - -
-
+

Search Todo

+
+
+
+ + +
+ +
{%endblock%} diff --git a/web-application/todo_list/template/todo/update_todo.html b/web-application/todo_list/template/todo/update_todo.html index b8a093a..1eb1904 100644 --- a/web-application/todo_list/template/todo/update_todo.html +++ b/web-application/todo_list/template/todo/update_todo.html @@ -4,12 +4,15 @@ {%block body%}
-
-
- - - -
-
+

Update Todo

+
+
+
+ + +
+ + +
{%endblock%} diff --git a/web-application/todo_list/todo.db b/web-application/todo_list/todo.db new file mode 100644 index 0000000000000000000000000000000000000000..9182078acf223abcb188ba45876d7577e2b65220 GIT binary patch literal 12288 zcmeI&Jx|*}7zglkQt=WA4u-(`EU31WL~#s)(xoOn6$|4uu2YFAGT4Z#0#V5!b&a}p z@7|?zKLH=0Q>PB>MM$h&I&v3*6r@T-V(8HS*=PIixfk7UJKJyCp;S2?_D_#fMIKvV zmc?EWF~$~kF6w-jEdB80uAuLx{7_nCHT&Hh|HBINS8V=@|9Gea;t+rU1Rwwb2tWV= z5P$##AOL|!2n=&;dbwP-K2}w_-^*1$>ziC?#==hoCH__@$kdQsnw1#^Q6gT6n4(rf zQ6~&5RGL*%^>TXa$IWd&w%x{tb1ytlsX80bR;v{XKQbK-PV-ddSy##9oL=gAl3-Vu zz@a>mgQLGiUdO?%AMeqQ*dtqJj%nSAf_6ucJ(_=1)7%!#9kOp{3?j1Y6>=S?`gtHubsY z)jZFAw(jb2+mnwyLCX@q*8Bep#xM9a|2{znG=TsFAOHafKmY;|fB*y_009U<;NJ=G Y-}>MEv9wTJvBuvim@ocIWAWR^8%U3L9smFU literal 0 HcmV?d00001 diff --git a/web-application/todo_list/todo_web.py b/web-application/todo_list/todo_web.py index 3bcf10e..4fd70d9 100644 --- a/web-application/todo_list/todo_web.py +++ b/web-application/todo_list/todo_web.py @@ -106,6 +106,7 @@ def search_todo(): return render_template('todo/search_todo.html') elif request.method == 'POST': title = request.form.get('title') + print(title) todos = Todo.query.filter(Todo.title.like('%' + title + '%')).all() time = datetime.now() return render_template('todo/index.html', todos=todos, time=time) From 3b2a2c3fe7f9d0ae5cde749ebce803ac94bfc7f4 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Sun, 28 Oct 2018 21:51:06 +0800 Subject: [PATCH 08/16] finish todo website 95% --- README.md | 2 +- web-application/todo_list/Dockerfile | 1 - web-application/todo_list/gunicorn.config.py | 3 - .../static/bootstrap-datetimepicker.css | 418 ++++ .../static/bootstrap-datetimepicker.js | 1967 +++++++++++++++++ web-application/todo_list/template/base.html | 7 + .../todo_list/template/todo/add_todo.html | 29 +- .../todo_list/template/todo/index.html | 4 +- .../todo_list/template/todo/update_todo.html | 4 +- web-application/todo_list/todo.db | Bin 12288 -> 12288 bytes web-application/todo_list/todo_web.py | 17 +- 11 files changed, 2439 insertions(+), 13 deletions(-) delete mode 100644 web-application/todo_list/Dockerfile delete mode 100644 web-application/todo_list/gunicorn.config.py create mode 100644 web-application/todo_list/static/bootstrap-datetimepicker.css create mode 100644 web-application/todo_list/static/bootstrap-datetimepicker.js diff --git a/README.md b/README.md index 49d4659..63b9cf7 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ ### Web应用 -* ~~todo list, 可以管理todo清单, 并设定短信发送时间, 在指定时间发送短信.~~(half) +* ~~todo list, 可以管理todo清单, 并设定短信发送时间, 在指定时间发送短信.~~ * 所见即所得编辑器——创建一个在线编辑器,允许用户移动元素、创建表格、书写文本、设置颜色,而用户不必懂HTML。就像Dreamweaver或者FrontPage。如果需要例子的话,可以参看DIC。 * 分页浏览器——创建一个可以分页的小型网页浏览器,可以同时浏览几个网页。简化一点的话不要考虑Javascript或者其它客户端代码。 * 文件下载器——该程序可以从网页上下载各种资源,包括视频和其它文件。用于有很多下载链接的网页。 diff --git a/web-application/todo_list/Dockerfile b/web-application/todo_list/Dockerfile deleted file mode 100644 index 673ced6..0000000 --- a/web-application/todo_list/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM: python:3 diff --git a/web-application/todo_list/gunicorn.config.py b/web-application/todo_list/gunicorn.config.py deleted file mode 100644 index a62b8f2..0000000 --- a/web-application/todo_list/gunicorn.config.py +++ /dev/null @@ -1,3 +0,0 @@ -workers = 4 -worker_class = "gevent" -bind = "0.0.0.0:8888" diff --git a/web-application/todo_list/static/bootstrap-datetimepicker.css b/web-application/todo_list/static/bootstrap-datetimepicker.css new file mode 100644 index 0000000..537c6a4 --- /dev/null +++ b/web-application/todo_list/static/bootstrap-datetimepicker.css @@ -0,0 +1,418 @@ +/*! + * Datetimepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datetimepicker { + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; +} + +.datetimepicker-inline { + width: 220px; +} + +.datetimepicker.datetimepicker-rtl { + direction: rtl; +} + +.datetimepicker.datetimepicker-rtl table tr td span { + float: right; +} + +.datetimepicker-dropdown, .datetimepicker-dropdown-left { + top: 0; + left: 0; +} + +[class*=" datetimepicker-dropdown"]:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #cccccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} + +[class*=" datetimepicker-dropdown"]:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; +} + +[class*=" datetimepicker-dropdown-top"]:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-top: 7px solid #cccccc; + border-top-color: rgba(0, 0, 0, 0.2); + border-bottom: 0; +} + +[class*=" datetimepicker-dropdown-top"]:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.datetimepicker-dropdown-bottom-left:before { + top: -7px; + right: 6px; +} + +.datetimepicker-dropdown-bottom-left:after { + top: -6px; + right: 7px; +} + +.datetimepicker-dropdown-bottom-right:before { + top: -7px; + left: 6px; +} + +.datetimepicker-dropdown-bottom-right:after { + top: -6px; + left: 7px; +} + +.datetimepicker-dropdown-top-left:before { + bottom: -7px; + right: 6px; +} + +.datetimepicker-dropdown-top-left:after { + bottom: -6px; + right: 7px; +} + +.datetimepicker-dropdown-top-right:before { + bottom: -7px; + left: 6px; +} + +.datetimepicker-dropdown-top-right:after { + bottom: -6px; + left: 7px; +} + +.datetimepicker > div { + display: none; +} + +.datetimepicker.minutes div.datetimepicker-minutes { + display: block; +} + +.datetimepicker.hours div.datetimepicker-hours { + display: block; +} + +.datetimepicker.days div.datetimepicker-days { + display: block; +} + +.datetimepicker.months div.datetimepicker-months { + display: block; +} + +.datetimepicker.years div.datetimepicker-years { + display: block; +} + +.datetimepicker table { + margin: 0; +} + +.datetimepicker td, +.datetimepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} + +.table-striped .datetimepicker table tr td, +.table-striped .datetimepicker table tr th { + background-color: transparent; +} + +.datetimepicker table tr td.minute:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.hour:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} + +.datetimepicker table tr td.old, +.datetimepicker table tr td.new { + color: #999999; +} + +.datetimepicker table tr td.disabled, +.datetimepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} + +.datetimepicker table tr td.today, +.datetimepicker table tr td.today:hover, +.datetimepicker table tr td.today.disabled, +.datetimepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(to bottom, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.datetimepicker table tr td.today:hover, +.datetimepicker table tr td.today:hover:hover, +.datetimepicker table tr td.today.disabled:hover, +.datetimepicker table tr td.today.disabled:hover:hover, +.datetimepicker table tr td.today:active, +.datetimepicker table tr td.today:hover:active, +.datetimepicker table tr td.today.disabled:active, +.datetimepicker table tr td.today.disabled:hover:active, +.datetimepicker table tr td.today.active, +.datetimepicker table tr td.today:hover.active, +.datetimepicker table tr td.today.disabled.active, +.datetimepicker table tr td.today.disabled:hover.active, +.datetimepicker table tr td.today.disabled, +.datetimepicker table tr td.today:hover.disabled, +.datetimepicker table tr td.today.disabled.disabled, +.datetimepicker table tr td.today.disabled:hover.disabled, +.datetimepicker table tr td.today[disabled], +.datetimepicker table tr td.today:hover[disabled], +.datetimepicker table tr td.today.disabled[disabled], +.datetimepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} + +.datetimepicker table tr td.today:active, +.datetimepicker table tr td.today:hover:active, +.datetimepicker table tr td.today.disabled:active, +.datetimepicker table tr td.today.disabled:hover:active, +.datetimepicker table tr td.today.active, +.datetimepicker table tr td.today:hover.active, +.datetimepicker table tr td.today.disabled.active, +.datetimepicker table tr td.today.disabled:hover.active { + background-color: #fbf069; +} + +.datetimepicker table tr td.active, +.datetimepicker table tr td.active:hover, +.datetimepicker table tr td.active.disabled, +.datetimepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.datetimepicker table tr td.active:hover, +.datetimepicker table tr td.active:hover:hover, +.datetimepicker table tr td.active.disabled:hover, +.datetimepicker table tr td.active.disabled:hover:hover, +.datetimepicker table tr td.active:active, +.datetimepicker table tr td.active:hover:active, +.datetimepicker table tr td.active.disabled:active, +.datetimepicker table tr td.active.disabled:hover:active, +.datetimepicker table tr td.active.active, +.datetimepicker table tr td.active:hover.active, +.datetimepicker table tr td.active.disabled.active, +.datetimepicker table tr td.active.disabled:hover.active, +.datetimepicker table tr td.active.disabled, +.datetimepicker table tr td.active:hover.disabled, +.datetimepicker table tr td.active.disabled.disabled, +.datetimepicker table tr td.active.disabled:hover.disabled, +.datetimepicker table tr td.active[disabled], +.datetimepicker table tr td.active:hover[disabled], +.datetimepicker table tr td.active.disabled[disabled], +.datetimepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} + +.datetimepicker table tr td.active:active, +.datetimepicker table tr td.active:hover:active, +.datetimepicker table tr td.active.disabled:active, +.datetimepicker table tr td.active.disabled:hover:active, +.datetimepicker table tr td.active.active, +.datetimepicker table tr td.active:hover.active, +.datetimepicker table tr td.active.disabled.active, +.datetimepicker table tr td.active.disabled:hover.active { + background-color: #003399; +} + +.datetimepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.datetimepicker .datetimepicker-hours span { + height: 26px; + line-height: 26px; +} + +.datetimepicker .datetimepicker-hours table tr td span.hour_am, +.datetimepicker .datetimepicker-hours table tr td span.hour_pm { + width: 14.6%; +} + +.datetimepicker .datetimepicker-hours fieldset legend, +.datetimepicker .datetimepicker-minutes fieldset legend { + margin-bottom: inherit; + line-height: 30px; +} + +.datetimepicker .datetimepicker-minutes span { + height: 26px; + line-height: 26px; +} + +.datetimepicker table tr td span:hover { + background: #eeeeee; +} + +.datetimepicker table tr td span.disabled, +.datetimepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} + +.datetimepicker table tr td span.active, +.datetimepicker table tr td span.active:hover, +.datetimepicker table tr td span.active.disabled, +.datetimepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.datetimepicker table tr td span.active:hover, +.datetimepicker table tr td span.active:hover:hover, +.datetimepicker table tr td span.active.disabled:hover, +.datetimepicker table tr td span.active.disabled:hover:hover, +.datetimepicker table tr td span.active:active, +.datetimepicker table tr td span.active:hover:active, +.datetimepicker table tr td span.active.disabled:active, +.datetimepicker table tr td span.active.disabled:hover:active, +.datetimepicker table tr td span.active.active, +.datetimepicker table tr td span.active:hover.active, +.datetimepicker table tr td span.active.disabled.active, +.datetimepicker table tr td span.active.disabled:hover.active, +.datetimepicker table tr td span.active.disabled, +.datetimepicker table tr td span.active:hover.disabled, +.datetimepicker table tr td span.active.disabled.disabled, +.datetimepicker table tr td span.active.disabled:hover.disabled, +.datetimepicker table tr td span.active[disabled], +.datetimepicker table tr td span.active:hover[disabled], +.datetimepicker table tr td span.active.disabled[disabled], +.datetimepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} + +.datetimepicker table tr td span.active:active, +.datetimepicker table tr td span.active:hover:active, +.datetimepicker table tr td span.active.disabled:active, +.datetimepicker table tr td span.active.disabled:hover:active, +.datetimepicker table tr td span.active.active, +.datetimepicker table tr td span.active:hover.active, +.datetimepicker table tr td span.active.disabled.active, +.datetimepicker table tr td span.active.disabled:hover.active { + background-color: #003399; +} + +.datetimepicker table tr td span.old { + color: #999999; +} + +.datetimepicker th.switch { + width: 145px; +} + +.datetimepicker th span.glyphicon { + pointer-events: none; +} + +.datetimepicker thead tr:first-child th, +.datetimepicker tfoot th { + cursor: pointer; +} + +.datetimepicker thead tr:first-child th:hover, +.datetimepicker tfoot th:hover { + background: #eeeeee; +} + +.input-append.date .add-on i, +.input-prepend.date .add-on i, +.input-group.date .input-group-addon span { + cursor: pointer; + width: 14px; + height: 14px; +} diff --git a/web-application/todo_list/static/bootstrap-datetimepicker.js b/web-application/todo_list/static/bootstrap-datetimepicker.js new file mode 100644 index 0000000..f66d69c --- /dev/null +++ b/web-application/todo_list/static/bootstrap-datetimepicker.js @@ -0,0 +1,1967 @@ +/* ========================================================= + * bootstrap-datetimepicker.js + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Improvements by Andrew Rowls + * Improvements by Sébastien Malot + * Improvements by Yun Lai + * Improvements by Kenneth Henderick + * Improvements by CuGBabyBeaR + * Improvements by Christian Vaas + * + * Project URL : http://www.malot.fr/bootstrap-datetimepicker + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +(function(factory){ + if (typeof define === 'function' && define.amd) + define(['jquery'], factory); + else if (typeof exports === 'object') + factory(require('jquery')); + else + factory(jQuery); + +}(function($, undefined){ + + // Add ECMA262-5 Array methods if not supported natively (IE8) + if (!('indexOf' in Array.prototype)) { + Array.prototype.indexOf = function (find, i) { + if (i === undefined) i = 0; + if (i < 0) i += this.length; + if (i < 0) i = 0; + for (var n = this.length; i < n; i++) { + if (i in this && this[i] === find) { + return i; + } + } + return -1; + } + } + + // Add timezone abbreviation support for ie6+, Chrome, Firefox + function timeZoneAbbreviation() { + var abbreviation, date, formattedStr, i, len, matchedStrings, ref, str; + date = (new Date()).toString(); + formattedStr = ((ref = date.split('(')[1]) != null ? ref.slice(0, -1) : 0) || date.split(' '); + if (formattedStr instanceof Array) { + matchedStrings = []; + for (var i = 0, len = formattedStr.length; i < len; i++) { + str = formattedStr[i]; + if ((abbreviation = (ref = str.match(/\b[A-Z]+\b/)) !== null) ? ref[0] : 0) { + matchedStrings.push(abbreviation); + } + } + formattedStr = matchedStrings.pop(); + } + return formattedStr; + } + + function UTCDate() { + return new Date(Date.UTC.apply(Date, arguments)); + } + + // Picker object + var Datetimepicker = function (element, options) { + var that = this; + + this.element = $(element); + + // add container for single page application + // when page switch the datetimepicker div will be removed also. + this.container = options.container || 'body'; + + this.language = options.language || this.element.data('date-language') || 'en'; + this.language = this.language in dates ? this.language : this.language.split('-')[0]; // fr-CA fallback to fr + this.language = this.language in dates ? this.language : 'en'; + this.isRTL = dates[this.language].rtl || false; + this.formatType = options.formatType || this.element.data('format-type') || 'standard'; + this.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || dates[this.language].format || DPGlobal.getDefaultFormat(this.formatType, 'input'), this.formatType); + this.isInline = false; + this.isVisible = false; + this.isInput = this.element.is('input'); + this.fontAwesome = options.fontAwesome || this.element.data('font-awesome') || false; + + this.bootcssVer = options.bootcssVer || (this.isInput ? (this.element.is('.form-control') ? 3 : 2) : ( this.bootcssVer = this.element.is('.input-group') ? 3 : 2 )); + + this.component = this.element.is('.date') ? ( this.bootcssVer === 3 ? this.element.find('.input-group-addon .glyphicon-th, .input-group-addon .glyphicon-time, .input-group-addon .glyphicon-remove, .input-group-addon .glyphicon-calendar, .input-group-addon .fa-calendar, .input-group-addon .fa-clock-o').parent() : this.element.find('.add-on .icon-th, .add-on .icon-time, .add-on .icon-calendar, .add-on .fa-calendar, .add-on .fa-clock-o').parent()) : false; + this.componentReset = this.element.is('.date') ? ( this.bootcssVer === 3 ? this.element.find('.input-group-addon .glyphicon-remove, .input-group-addon .fa-times').parent():this.element.find('.add-on .icon-remove, .add-on .fa-times').parent()) : false; + this.hasInput = this.component && this.element.find('input').length; + if (this.component && this.component.length === 0) { + this.component = false; + } + this.linkField = options.linkField || this.element.data('link-field') || false; + this.linkFormat = DPGlobal.parseFormat(options.linkFormat || this.element.data('link-format') || DPGlobal.getDefaultFormat(this.formatType, 'link'), this.formatType); + this.minuteStep = options.minuteStep || this.element.data('minute-step') || 5; + this.pickerPosition = options.pickerPosition || this.element.data('picker-position') || 'bottom-right'; + this.showMeridian = options.showMeridian || this.element.data('show-meridian') || false; + this.initialDate = options.initialDate || new Date(); + this.zIndex = options.zIndex || this.element.data('z-index') || undefined; + this.title = typeof options.title === 'undefined' ? false : options.title; + this.timezone = options.timezone || timeZoneAbbreviation(); + + this.icons = { + leftArrow: this.fontAwesome ? 'fa-arrow-left' : (this.bootcssVer === 3 ? 'glyphicon-arrow-left' : 'icon-arrow-left'), + rightArrow: this.fontAwesome ? 'fa-arrow-right' : (this.bootcssVer === 3 ? 'glyphicon-arrow-right' : 'icon-arrow-right') + } + this.icontype = this.fontAwesome ? 'fa' : 'glyphicon'; + + this._attachEvents(); + + this.clickedOutside = function (e) { + // Clicked outside the datetimepicker, hide it + if ($(e.target).closest('.datetimepicker').length === 0) { + that.hide(); + } + } + + this.formatViewType = 'datetime'; + if ('formatViewType' in options) { + this.formatViewType = options.formatViewType; + } else if ('formatViewType' in this.element.data()) { + this.formatViewType = this.element.data('formatViewType'); + } + + this.minView = 0; + if ('minView' in options) { + this.minView = options.minView; + } else if ('minView' in this.element.data()) { + this.minView = this.element.data('min-view'); + } + this.minView = DPGlobal.convertViewMode(this.minView); + + this.maxView = DPGlobal.modes.length - 1; + if ('maxView' in options) { + this.maxView = options.maxView; + } else if ('maxView' in this.element.data()) { + this.maxView = this.element.data('max-view'); + } + this.maxView = DPGlobal.convertViewMode(this.maxView); + + this.wheelViewModeNavigation = false; + if ('wheelViewModeNavigation' in options) { + this.wheelViewModeNavigation = options.wheelViewModeNavigation; + } else if ('wheelViewModeNavigation' in this.element.data()) { + this.wheelViewModeNavigation = this.element.data('view-mode-wheel-navigation'); + } + + this.wheelViewModeNavigationInverseDirection = false; + + if ('wheelViewModeNavigationInverseDirection' in options) { + this.wheelViewModeNavigationInverseDirection = options.wheelViewModeNavigationInverseDirection; + } else if ('wheelViewModeNavigationInverseDirection' in this.element.data()) { + this.wheelViewModeNavigationInverseDirection = this.element.data('view-mode-wheel-navigation-inverse-dir'); + } + + this.wheelViewModeNavigationDelay = 100; + if ('wheelViewModeNavigationDelay' in options) { + this.wheelViewModeNavigationDelay = options.wheelViewModeNavigationDelay; + } else if ('wheelViewModeNavigationDelay' in this.element.data()) { + this.wheelViewModeNavigationDelay = this.element.data('view-mode-wheel-navigation-delay'); + } + + this.startViewMode = 2; + if ('startView' in options) { + this.startViewMode = options.startView; + } else if ('startView' in this.element.data()) { + this.startViewMode = this.element.data('start-view'); + } + this.startViewMode = DPGlobal.convertViewMode(this.startViewMode); + this.viewMode = this.startViewMode; + + this.viewSelect = this.minView; + if ('viewSelect' in options) { + this.viewSelect = options.viewSelect; + } else if ('viewSelect' in this.element.data()) { + this.viewSelect = this.element.data('view-select'); + } + this.viewSelect = DPGlobal.convertViewMode(this.viewSelect); + + this.forceParse = true; + if ('forceParse' in options) { + this.forceParse = options.forceParse; + } else if ('dateForceParse' in this.element.data()) { + this.forceParse = this.element.data('date-force-parse'); + } + var template = this.bootcssVer === 3 ? DPGlobal.templateV3 : DPGlobal.template; + while (template.indexOf('{iconType}') !== -1) { + template = template.replace('{iconType}', this.icontype); + } + while (template.indexOf('{leftArrow}') !== -1) { + template = template.replace('{leftArrow}', this.icons.leftArrow); + } + while (template.indexOf('{rightArrow}') !== -1) { + template = template.replace('{rightArrow}', this.icons.rightArrow); + } + this.picker = $(template) + .appendTo(this.isInline ? this.element : this.container) // 'body') + .on({ + click: $.proxy(this.click, this), + mousedown: $.proxy(this.mousedown, this) + }); + + if (this.wheelViewModeNavigation) { + if ($.fn.mousewheel) { + this.picker.on({mousewheel: $.proxy(this.mousewheel, this)}); + } else { + console.log('Mouse Wheel event is not supported. Please include the jQuery Mouse Wheel plugin before enabling this option'); + } + } + + if (this.isInline) { + this.picker.addClass('datetimepicker-inline'); + } else { + this.picker.addClass('datetimepicker-dropdown-' + this.pickerPosition + ' dropdown-menu'); + } + if (this.isRTL) { + this.picker.addClass('datetimepicker-rtl'); + var selector = this.bootcssVer === 3 ? '.prev span, .next span' : '.prev i, .next i'; + this.picker.find(selector).toggleClass(this.icons.leftArrow + ' ' + this.icons.rightArrow); + } + + $(document).on('mousedown touchend', this.clickedOutside); + + this.autoclose = false; + if ('autoclose' in options) { + this.autoclose = options.autoclose; + } else if ('dateAutoclose' in this.element.data()) { + this.autoclose = this.element.data('date-autoclose'); + } + + this.keyboardNavigation = true; + if ('keyboardNavigation' in options) { + this.keyboardNavigation = options.keyboardNavigation; + } else if ('dateKeyboardNavigation' in this.element.data()) { + this.keyboardNavigation = this.element.data('date-keyboard-navigation'); + } + + this.todayBtn = (options.todayBtn || this.element.data('date-today-btn') || false); + this.clearBtn = (options.clearBtn || this.element.data('date-clear-btn') || false); + this.todayHighlight = (options.todayHighlight || this.element.data('date-today-highlight') || false); + + this.weekStart = 0; + if (typeof options.weekStart !== 'undefined') { + this.weekStart = options.weekStart; + } else if (typeof this.element.data('date-weekstart') !== 'undefined') { + this.weekStart = this.element.data('date-weekstart'); + } else if (typeof dates[this.language].weekStart !== 'undefined') { + this.weekStart = dates[this.language].weekStart; + } + this.weekStart = this.weekStart % 7; + this.weekEnd = ((this.weekStart + 6) % 7); + this.onRenderDay = function (date) { + var render = (options.onRenderDay || function () { return []; })(date); + if (typeof render === 'string') { + render = [render]; + } + var res = ['day']; + return res.concat((render ? render : [])); + }; + this.onRenderHour = function (date) { + var render = (options.onRenderHour || function () { return []; })(date); + var res = ['hour']; + if (typeof render === 'string') { + render = [render]; + } + return res.concat((render ? render : [])); + }; + this.onRenderMinute = function (date) { + var render = (options.onRenderMinute || function () { return []; })(date); + var res = ['minute']; + if (typeof render === 'string') { + render = [render]; + } + if (date < this.startDate || date > this.endDate) { + res.push('disabled'); + } else if (Math.floor(this.date.getUTCMinutes() / this.minuteStep) === Math.floor(date.getUTCMinutes() / this.minuteStep)) { + res.push('active'); + } + return res.concat((render ? render : [])); + }; + this.onRenderYear = function (date) { + var render = (options.onRenderYear || function () { return []; })(date); + var res = ['year']; + if (typeof render === 'string') { + render = [render]; + } + if (this.date.getUTCFullYear() === date.getUTCFullYear()) { + res.push('active'); + } + var currentYear = date.getUTCFullYear(); + var endYear = this.endDate.getUTCFullYear(); + if (date < this.startDate || currentYear > endYear) { + res.push('disabled'); + } + return res.concat((render ? render : [])); + } + this.onRenderMonth = function (date) { + var render = (options.onRenderMonth || function () { return []; })(date); + var res = ['month']; + if (typeof render === 'string') { + render = [render]; + } + return res.concat((render ? render : [])); + } + this.startDate = new Date(-8639968443048000); + this.endDate = new Date(8639968443048000); + this.datesDisabled = []; + this.daysOfWeekDisabled = []; + this.setStartDate(options.startDate || this.element.data('date-startdate')); + this.setEndDate(options.endDate || this.element.data('date-enddate')); + this.setDatesDisabled(options.datesDisabled || this.element.data('date-dates-disabled')); + this.setDaysOfWeekDisabled(options.daysOfWeekDisabled || this.element.data('date-days-of-week-disabled')); + this.setMinutesDisabled(options.minutesDisabled || this.element.data('date-minute-disabled')); + this.setHoursDisabled(options.hoursDisabled || this.element.data('date-hour-disabled')); + this.fillDow(); + this.fillMonths(); + this.update(); + this.showMode(); + + if (this.isInline) { + this.show(); + } + }; + + Datetimepicker.prototype = { + constructor: Datetimepicker, + + _events: [], + _attachEvents: function () { + this._detachEvents(); + if (this.isInput) { // single input + this._events = [ + [this.element, { + focus: $.proxy(this.show, this), + keyup: $.proxy(this.update, this), + keydown: $.proxy(this.keydown, this) + }] + ]; + } + else if (this.component && this.hasInput) { // component: input + button + this._events = [ + // For components that are not readonly, allow keyboard nav + [this.element.find('input'), { + focus: $.proxy(this.show, this), + keyup: $.proxy(this.update, this), + keydown: $.proxy(this.keydown, this) + }], + [this.component, { + click: $.proxy(this.show, this) + }] + ]; + if (this.componentReset) { + this._events.push([ + this.componentReset, + {click: $.proxy(this.reset, this)} + ]); + } + } + else if (this.element.is('div')) { // inline datetimepicker + this.isInline = true; + } + else { + this._events = [ + [this.element, { + click: $.proxy(this.show, this) + }] + ]; + } + for (var i = 0, el, ev; i < this._events.length; i++) { + el = this._events[i][0]; + ev = this._events[i][1]; + el.on(ev); + } + }, + + _detachEvents: function () { + for (var i = 0, el, ev; i < this._events.length; i++) { + el = this._events[i][0]; + ev = this._events[i][1]; + el.off(ev); + } + this._events = []; + }, + + show: function (e) { + this.picker.show(); + this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); + if (this.forceParse) { + this.update(); + } + this.place(); + $(window).on('resize', $.proxy(this.place, this)); + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + this.isVisible = true; + this.element.trigger({ + type: 'show', + date: this.date + }); + }, + + hide: function () { + if (!this.isVisible) return; + if (this.isInline) return; + this.picker.hide(); + $(window).off('resize', this.place); + this.viewMode = this.startViewMode; + this.showMode(); + if (!this.isInput) { + $(document).off('mousedown', this.hide); + } + + if ( + this.forceParse && + ( + this.isInput && this.element.val() || + this.hasInput && this.element.find('input').val() + ) + ) + this.setValue(); + this.isVisible = false; + this.element.trigger({ + type: 'hide', + date: this.date + }); + }, + + remove: function () { + this._detachEvents(); + $(document).off('mousedown', this.clickedOutside); + this.picker.remove(); + delete this.picker; + delete this.element.data().datetimepicker; + }, + + getDate: function () { + var d = this.getUTCDate(); + if (d === null) { + return null; + } + return new Date(d.getTime() + (d.getTimezoneOffset() * 60000)); + }, + + getUTCDate: function () { + return this.date; + }, + + getInitialDate: function () { + return this.initialDate + }, + + setInitialDate: function (initialDate) { + this.initialDate = initialDate; + }, + + setDate: function (d) { + this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset() * 60000))); + }, + + setUTCDate: function (d) { + if (d >= this.startDate && d <= this.endDate) { + this.date = d; + this.setValue(); + this.viewDate = this.date; + this.fill(); + } else { + this.element.trigger({ + type: 'outOfRange', + date: d, + startDate: this.startDate, + endDate: this.endDate + }); + } + }, + + setFormat: function (format) { + this.format = DPGlobal.parseFormat(format, this.formatType); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component) { + element = this.element.find('input'); + } + if (element && element.val()) { + this.setValue(); + } + }, + + setValue: function () { + var formatted = this.getFormattedDate(); + if (!this.isInput) { + if (this.component) { + this.element.find('input').val(formatted); + } + this.element.data('date', formatted); + } else { + this.element.val(formatted); + } + if (this.linkField) { + $('#' + this.linkField).val(this.getFormattedDate(this.linkFormat)); + } + }, + + getFormattedDate: function (format) { + format = format || this.format; + return DPGlobal.formatDate(this.date, format, this.language, this.formatType, this.timezone); + }, + + setStartDate: function (startDate) { + this.startDate = startDate || this.startDate; + if (this.startDate.valueOf() !== 8639968443048000) { + this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language, this.formatType, this.timezone); + } + this.update(); + this.updateNavArrows(); + }, + + setEndDate: function (endDate) { + this.endDate = endDate || this.endDate; + if (this.endDate.valueOf() !== 8639968443048000) { + this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language, this.formatType, this.timezone); + } + this.update(); + this.updateNavArrows(); + }, + + setDatesDisabled: function (datesDisabled) { + this.datesDisabled = datesDisabled || []; + if (!$.isArray(this.datesDisabled)) { + this.datesDisabled = this.datesDisabled.split(/,\s*/); + } + var mThis = this; + this.datesDisabled = $.map(this.datesDisabled, function (d) { + return DPGlobal.parseDate(d, mThis.format, mThis.language, mThis.formatType, mThis.timezone).toDateString(); + }); + this.update(); + this.updateNavArrows(); + }, + + setTitle: function (selector, value) { + return this.picker.find(selector) + .find('th:eq(1)') + .text(this.title === false ? value : this.title); + }, + + setDaysOfWeekDisabled: function (daysOfWeekDisabled) { + this.daysOfWeekDisabled = daysOfWeekDisabled || []; + if (!$.isArray(this.daysOfWeekDisabled)) { + this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/); + } + this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) { + return parseInt(d, 10); + }); + this.update(); + this.updateNavArrows(); + }, + + setMinutesDisabled: function (minutesDisabled) { + this.minutesDisabled = minutesDisabled || []; + if (!$.isArray(this.minutesDisabled)) { + this.minutesDisabled = this.minutesDisabled.split(/,\s*/); + } + this.minutesDisabled = $.map(this.minutesDisabled, function (d) { + return parseInt(d, 10); + }); + this.update(); + this.updateNavArrows(); + }, + + setHoursDisabled: function (hoursDisabled) { + this.hoursDisabled = hoursDisabled || []; + if (!$.isArray(this.hoursDisabled)) { + this.hoursDisabled = this.hoursDisabled.split(/,\s*/); + } + this.hoursDisabled = $.map(this.hoursDisabled, function (d) { + return parseInt(d, 10); + }); + this.update(); + this.updateNavArrows(); + }, + + place: function () { + if (this.isInline) return; + + if (!this.zIndex) { + var index_highest = 0; + $('div').each(function () { + var index_current = parseInt($(this).css('zIndex'), 10); + if (index_current > index_highest) { + index_highest = index_current; + } + }); + this.zIndex = index_highest + 10; + } + + var offset, top, left, containerOffset; + if (this.container instanceof $) { + containerOffset = this.container.offset(); + } else { + containerOffset = $(this.container).offset(); + } + + if (this.component) { + offset = this.component.offset(); + left = offset.left; + if (this.pickerPosition === 'bottom-left' || this.pickerPosition === 'top-left') { + left += this.component.outerWidth() - this.picker.outerWidth(); + } + } else { + offset = this.element.offset(); + left = offset.left; + if (this.pickerPosition === 'bottom-left' || this.pickerPosition === 'top-left') { + left += this.element.outerWidth() - this.picker.outerWidth(); + } + } + + var bodyWidth = document.body.clientWidth || window.innerWidth; + if (left + 220 > bodyWidth) { + left = bodyWidth - 220; + } + + if (this.pickerPosition === 'top-left' || this.pickerPosition === 'top-right') { + top = offset.top - this.picker.outerHeight(); + } else { + top = offset.top + this.height; + } + + top = top - containerOffset.top; + left = left - containerOffset.left; + + this.picker.css({ + top: top, + left: left, + zIndex: this.zIndex + }); + }, + + hour_minute: "^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]", + + update: function () { + var date, fromArgs = false; + if (arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) { + date = arguments[0]; + fromArgs = true; + } else { + date = (this.isInput ? this.element.val() : this.element.find('input').val()) || this.element.data('date') || this.initialDate; + if (typeof date === 'string') { + date = date.replace(/^\s+|\s+$/g,''); + } + } + + if (!date) { + date = new Date(); + fromArgs = false; + } + + if (typeof date === "string") { + if (new RegExp(this.hour_minute).test(date) || new RegExp(this.hour_minute + ":[0-5][0-9]").test(date)) { + date = this.getDate() + } + } + + this.date = DPGlobal.parseDate(date, this.format, this.language, this.formatType, this.timezone); + + if (fromArgs) this.setValue(); + + if (this.date < this.startDate) { + this.viewDate = new Date(this.startDate); + } else if (this.date > this.endDate) { + this.viewDate = new Date(this.endDate); + } else { + this.viewDate = new Date(this.date); + } + this.fill(); + }, + + fillDow: function () { + var dowCnt = this.weekStart, + html = ''; + while (dowCnt < this.weekStart + 7) { + html += '' + dates[this.language].daysMin[(dowCnt++) % 7] + ''; + } + html += ''; + this.picker.find('.datetimepicker-days thead').append(html); + }, + + fillMonths: function () { + var html = ''; + var d = new Date(this.viewDate); + for (var i = 0; i < 12; i++) { + d.setUTCMonth(i); + var classes = this.onRenderMonth(d); + html += '' + dates[this.language].monthsShort[i] + ''; + } + this.picker.find('.datetimepicker-months td').html(html); + }, + + fill: function () { + if (!this.date || !this.viewDate) { + return; + } + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + dayMonth = d.getUTCDate(), + hours = d.getUTCHours(), + startYear = this.startDate.getUTCFullYear(), + startMonth = this.startDate.getUTCMonth(), + endYear = this.endDate.getUTCFullYear(), + endMonth = this.endDate.getUTCMonth() + 1, + currentDate = (new UTCDate(this.date.getUTCFullYear(), this.date.getUTCMonth(), this.date.getUTCDate())).valueOf(), + today = new Date(); + this.setTitle('.datetimepicker-days', dates[this.language].months[month] + ' ' + year) + if (this.formatViewType === 'time') { + var formatted = this.getFormattedDate(); + this.setTitle('.datetimepicker-hours', formatted); + this.setTitle('.datetimepicker-minutes', formatted); + } else { + this.setTitle('.datetimepicker-hours', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year); + this.setTitle('.datetimepicker-minutes', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year); + } + this.picker.find('tfoot th.today') + .text(dates[this.language].today || dates['en'].today) + .toggle(this.todayBtn !== false); + this.picker.find('tfoot th.clear') + .text(dates[this.language].clear || dates['en'].clear) + .toggle(this.clearBtn !== false); + this.updateNavArrows(); + this.fillMonths(); + var prevMonth = UTCDate(year, month - 1, 28, 0, 0, 0, 0), + day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7); + var nextMonth = new Date(prevMonth); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var classes; + while (prevMonth.valueOf() < nextMonth) { + if (prevMonth.getUTCDay() === this.weekStart) { + html.push(''); + } + classes = this.onRenderDay(prevMonth); + if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() === year && prevMonth.getUTCMonth() < month)) { + classes.push('old'); + } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() === year && prevMonth.getUTCMonth() > month)) { + classes.push('new'); + } + // Compare internal UTC date with local today, not UTC today + if (this.todayHighlight && + prevMonth.getUTCFullYear() === today.getFullYear() && + prevMonth.getUTCMonth() === today.getMonth() && + prevMonth.getUTCDate() === today.getDate()) { + classes.push('today'); + } + if (prevMonth.valueOf() === currentDate) { + classes.push('active'); + } + if ((prevMonth.valueOf() + 86400000) <= this.startDate || prevMonth.valueOf() > this.endDate || + $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1 || + $.inArray(prevMonth.toDateString(), this.datesDisabled) !== -1) { + classes.push('disabled'); + } + html.push('' + prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() === this.weekEnd) { + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate() + 1); + } + this.picker.find('.datetimepicker-days tbody').empty().append(html.join('')); + + html = []; + var txt = '', meridian = '', meridianOld = ''; + var hoursDisabled = this.hoursDisabled || []; + d = new Date(this.viewDate) + for (var i = 0; i < 24; i++) { + d.setUTCHours(i); + classes = this.onRenderHour(d); + if (hoursDisabled.indexOf(i) !== -1) { + classes.push('disabled'); + } + var actual = UTCDate(year, month, dayMonth, i); + // We want the previous hour for the startDate + if ((actual.valueOf() + 3600000) <= this.startDate || actual.valueOf() > this.endDate) { + classes.push('disabled'); + } else if (hours === i) { + classes.push('active'); + } + if (this.showMeridian && dates[this.language].meridiem.length === 2) { + meridian = (i < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]); + if (meridian !== meridianOld) { + if (meridianOld !== '') { + html.push(''); + } + html.push('
' + meridian.toUpperCase() + ''); + } + meridianOld = meridian; + txt = (i % 12 ? i % 12 : 12); + if (i < 12) { + classes.push('hour_am'); + } else { + classes.push('hour_pm'); + } + html.push('' + txt + ''); + if (i === 23) { + html.push('
'); + } + } else { + txt = i + ':00'; + html.push('' + txt + ''); + } + } + this.picker.find('.datetimepicker-hours td').html(html.join('')); + + html = []; + txt = ''; + meridian = ''; + meridianOld = ''; + var minutesDisabled = this.minutesDisabled || []; + d = new Date(this.viewDate); + for (var i = 0; i < 60; i += this.minuteStep) { + if (minutesDisabled.indexOf(i) !== -1) continue; + d.setUTCMinutes(i); + d.setUTCSeconds(0); + classes = this.onRenderMinute(d); + if (this.showMeridian && dates[this.language].meridiem.length === 2) { + meridian = (hours < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]); + if (meridian !== meridianOld) { + if (meridianOld !== '') { + html.push(''); + } + html.push('
' + meridian.toUpperCase() + ''); + } + meridianOld = meridian; + txt = (hours % 12 ? hours % 12 : 12); + html.push('' + txt + ':' + (i < 10 ? '0' + i : i) + ''); + if (i === 59) { + html.push('
'); + } + } else { + txt = i + ':00'; + html.push('' + hours + ':' + (i < 10 ? '0' + i : i) + ''); + } + } + this.picker.find('.datetimepicker-minutes td').html(html.join('')); + + var currentYear = this.date.getUTCFullYear(); + var months = this.setTitle('.datetimepicker-months', year) + .end() + .find('.month').removeClass('active'); + if (currentYear === year) { + // getUTCMonths() returns 0 based, and we need to select the next one + // To cater bootstrap 2 we don't need to select the next one + months.eq(this.date.getUTCMonth()).addClass('active'); + } + if (year < startYear || year > endYear) { + months.addClass('disabled'); + } + if (year === startYear) { + months.slice(0, startMonth).addClass('disabled'); + } + if (year === endYear) { + months.slice(endMonth).addClass('disabled'); + } + + html = ''; + year = parseInt(year / 10, 10) * 10; + var yearCont = this.setTitle('.datetimepicker-years', year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + d = new Date(this.viewDate); + for (var i = -1; i < 11; i++) { + d.setUTCFullYear(year); + classes = this.onRenderYear(d); + if (i === -1 || i === 10) { + classes.push(old); + } + html += '' + year + ''; + year += 1; + } + yearCont.html(html); + this.place(); + }, + + updateNavArrows: function () { + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + day = d.getUTCDate(), + hour = d.getUTCHours(); + switch (this.viewMode) { + case 0: + if (year <= this.startDate.getUTCFullYear() + && month <= this.startDate.getUTCMonth() + && day <= this.startDate.getUTCDate() + && hour <= this.startDate.getUTCHours()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (year >= this.endDate.getUTCFullYear() + && month >= this.endDate.getUTCMonth() + && day >= this.endDate.getUTCDate() + && hour >= this.endDate.getUTCHours()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 1: + if (year <= this.startDate.getUTCFullYear() + && month <= this.startDate.getUTCMonth() + && day <= this.startDate.getUTCDate()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (year >= this.endDate.getUTCFullYear() + && month >= this.endDate.getUTCMonth() + && day >= this.endDate.getUTCDate()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 2: + if (year <= this.startDate.getUTCFullYear() + && month <= this.startDate.getUTCMonth()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (year >= this.endDate.getUTCFullYear() + && month >= this.endDate.getUTCMonth()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 3: + case 4: + if (year <= this.startDate.getUTCFullYear()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (year >= this.endDate.getUTCFullYear()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + } + }, + + mousewheel: function (e) { + + e.preventDefault(); + e.stopPropagation(); + + if (this.wheelPause) { + return; + } + + this.wheelPause = true; + + var originalEvent = e.originalEvent; + + var delta = originalEvent.wheelDelta; + + var mode = delta > 0 ? 1 : (delta === 0) ? 0 : -1; + + if (this.wheelViewModeNavigationInverseDirection) { + mode = -mode; + } + + this.showMode(mode); + + setTimeout($.proxy(function () { + + this.wheelPause = false + + }, this), this.wheelViewModeNavigationDelay); + + }, + + click: function (e) { + e.stopPropagation(); + e.preventDefault(); + var target = $(e.target).closest('span, td, th, legend'); + if (target.is('.' + this.icontype)) { + target = $(target).parent().closest('span, td, th, legend'); + } + if (target.length === 1) { + if (target.is('.disabled')) { + this.element.trigger({ + type: 'outOfRange', + date: this.viewDate, + startDate: this.startDate, + endDate: this.endDate + }); + return; + } + switch (target[0].nodeName.toLowerCase()) { + case 'th': + switch (target[0].className) { + case 'switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1); + switch (this.viewMode) { + case 0: + this.viewDate = this.moveHour(this.viewDate, dir); + break; + case 1: + this.viewDate = this.moveDate(this.viewDate, dir); + break; + case 2: + this.viewDate = this.moveMonth(this.viewDate, dir); + break; + case 3: + case 4: + this.viewDate = this.moveYear(this.viewDate, dir); + break; + } + this.fill(); + this.element.trigger({ + type: target[0].className + ':' + this.convertViewModeText(this.viewMode), + date: this.viewDate, + startDate: this.startDate, + endDate: this.endDate + }); + break; + case 'clear': + this.reset(); + if (this.autoclose) { + this.hide(); + } + break; + case 'today': + var date = new Date(); + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0); + + // Respect startDate and endDate. + if (date < this.startDate) date = this.startDate; + else if (date > this.endDate) date = this.endDate; + + this.viewMode = this.startViewMode; + this.showMode(0); + this._setDate(date); + this.fill(); + if (this.autoclose) { + this.hide(); + } + break; + } + break; + case 'span': + if (!target.is('.disabled')) { + var year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(), + day = this.viewDate.getUTCDate(), + hours = this.viewDate.getUTCHours(), + minutes = this.viewDate.getUTCMinutes(), + seconds = this.viewDate.getUTCSeconds(); + + if (target.is('.month')) { + this.viewDate.setUTCDate(1); + month = target.parent().find('span').index(target); + day = this.viewDate.getUTCDate(); + this.viewDate.setUTCMonth(month); + this.element.trigger({ + type: 'changeMonth', + date: this.viewDate + }); + if (this.viewSelect >= 3) { + this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0)); + } + } else if (target.is('.year')) { + this.viewDate.setUTCDate(1); + year = parseInt(target.text(), 10) || 0; + this.viewDate.setUTCFullYear(year); + this.element.trigger({ + type: 'changeYear', + date: this.viewDate + }); + if (this.viewSelect >= 4) { + this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0)); + } + } else if (target.is('.hour')) { + hours = parseInt(target.text(), 10) || 0; + if (target.hasClass('hour_am') || target.hasClass('hour_pm')) { + if (hours === 12 && target.hasClass('hour_am')) { + hours = 0; + } else if (hours !== 12 && target.hasClass('hour_pm')) { + hours += 12; + } + } + this.viewDate.setUTCHours(hours); + this.element.trigger({ + type: 'changeHour', + date: this.viewDate + }); + if (this.viewSelect >= 1) { + this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0)); + } + } else if (target.is('.minute')) { + minutes = parseInt(target.text().substr(target.text().indexOf(':') + 1), 10) || 0; + this.viewDate.setUTCMinutes(minutes); + this.element.trigger({ + type: 'changeMinute', + date: this.viewDate + }); + if (this.viewSelect >= 0) { + this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0)); + } + } + if (this.viewMode !== 0) { + var oldViewMode = this.viewMode; + this.showMode(-1); + this.fill(); + if (oldViewMode === this.viewMode && this.autoclose) { + this.hide(); + } + } else { + this.fill(); + if (this.autoclose) { + this.hide(); + } + } + } + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')) { + var day = parseInt(target.text(), 10) || 1; + var year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(), + hours = this.viewDate.getUTCHours(), + minutes = this.viewDate.getUTCMinutes(), + seconds = this.viewDate.getUTCSeconds(); + if (target.is('.old')) { + if (month === 0) { + month = 11; + year -= 1; + } else { + month -= 1; + } + } else if (target.is('.new')) { + if (month === 11) { + month = 0; + year += 1; + } else { + month += 1; + } + } + this.viewDate.setUTCFullYear(year); + this.viewDate.setUTCMonth(month, day); + this.element.trigger({ + type: 'changeDay', + date: this.viewDate + }); + if (this.viewSelect >= 2) { + this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0)); + } + } + var oldViewMode = this.viewMode; + this.showMode(-1); + this.fill(); + if (oldViewMode === this.viewMode && this.autoclose) { + this.hide(); + } + break; + } + } + }, + + _setDate: function (date, which) { + if (!which || which === 'date') + this.date = date; + if (!which || which === 'view') + this.viewDate = date; + this.fill(); + this.setValue(); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component) { + element = this.element.find('input'); + } + if (element) { + element.change(); + } + this.element.trigger({ + type: 'changeDate', + date: this.getDate() + }); + if(date === null) + this.date = this.viewDate; + }, + + moveMinute: function (date, dir) { + if (!dir) return date; + var new_date = new Date(date.valueOf()); + //dir = dir > 0 ? 1 : -1; + new_date.setUTCMinutes(new_date.getUTCMinutes() + (dir * this.minuteStep)); + return new_date; + }, + + moveHour: function (date, dir) { + if (!dir) return date; + var new_date = new Date(date.valueOf()); + //dir = dir > 0 ? 1 : -1; + new_date.setUTCHours(new_date.getUTCHours() + dir); + return new_date; + }, + + moveDate: function (date, dir) { + if (!dir) return date; + var new_date = new Date(date.valueOf()); + //dir = dir > 0 ? 1 : -1; + new_date.setUTCDate(new_date.getUTCDate() + dir); + return new_date; + }, + + moveMonth: function (date, dir) { + if (!dir) return date; + var new_date = new Date(date.valueOf()), + day = new_date.getUTCDate(), + month = new_date.getUTCMonth(), + mag = Math.abs(dir), + new_month, test; + dir = dir > 0 ? 1 : -1; + if (mag === 1) { + test = dir === -1 + // If going back one month, make sure month is not current month + // (eg, Mar 31 -> Feb 31 === Feb 28, not Mar 02) + ? function () { + return new_date.getUTCMonth() === month; + } + // If going forward one month, make sure month is as expected + // (eg, Jan 31 -> Feb 31 === Feb 28, not Mar 02) + : function () { + return new_date.getUTCMonth() !== new_month; + }; + new_month = month + dir; + new_date.setUTCMonth(new_month); + // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 + if (new_month < 0 || new_month > 11) + new_month = (new_month + 12) % 12; + } else { + // For magnitudes >1, move one month at a time... + for (var i = 0; i < mag; i++) + // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... + new_date = this.moveMonth(new_date, dir); + // ...then reset the day, keeping it in the new month + new_month = new_date.getUTCMonth(); + new_date.setUTCDate(day); + test = function () { + return new_month !== new_date.getUTCMonth(); + }; + } + // Common date-resetting loop -- if date is beyond end of month, make it + // end of month + while (test()) { + new_date.setUTCDate(--day); + new_date.setUTCMonth(new_month); + } + return new_date; + }, + + moveYear: function (date, dir) { + return this.moveMonth(date, dir * 12); + }, + + dateWithinRange: function (date) { + return date >= this.startDate && date <= this.endDate; + }, + + keydown: function (e) { + if (this.picker.is(':not(:visible)')) { + if (e.keyCode === 27) // allow escape to hide and re-show picker + this.show(); + return; + } + var dateChanged = false, + dir, newDate, newViewDate; + switch (e.keyCode) { + case 27: // escape + this.hide(); + e.preventDefault(); + break; + case 37: // left + case 39: // right + if (!this.keyboardNavigation) break; + dir = e.keyCode === 37 ? -1 : 1; + var viewMode = this.viewMode; + if (e.ctrlKey) { + viewMode += 2; + } else if (e.shiftKey) { + viewMode += 1; + } + if (viewMode === 4) { + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (viewMode === 3) { + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else if (viewMode === 2) { + newDate = this.moveDate(this.date, dir); + newViewDate = this.moveDate(this.viewDate, dir); + } else if (viewMode === 1) { + newDate = this.moveHour(this.date, dir); + newViewDate = this.moveHour(this.viewDate, dir); + } else if (viewMode === 0) { + newDate = this.moveMinute(this.date, dir); + newViewDate = this.moveMinute(this.viewDate, dir); + } + if (this.dateWithinRange(newDate)) { + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 38: // up + case 40: // down + if (!this.keyboardNavigation) break; + dir = e.keyCode === 38 ? -1 : 1; + viewMode = this.viewMode; + if (e.ctrlKey) { + viewMode += 2; + } else if (e.shiftKey) { + viewMode += 1; + } + if (viewMode === 4) { + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (viewMode === 3) { + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else if (viewMode === 2) { + newDate = this.moveDate(this.date, dir * 7); + newViewDate = this.moveDate(this.viewDate, dir * 7); + } else if (viewMode === 1) { + if (this.showMeridian) { + newDate = this.moveHour(this.date, dir * 6); + newViewDate = this.moveHour(this.viewDate, dir * 6); + } else { + newDate = this.moveHour(this.date, dir * 4); + newViewDate = this.moveHour(this.viewDate, dir * 4); + } + } else if (viewMode === 0) { + newDate = this.moveMinute(this.date, dir * 4); + newViewDate = this.moveMinute(this.viewDate, dir * 4); + } + if (this.dateWithinRange(newDate)) { + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 13: // enter + if (this.viewMode !== 0) { + var oldViewMode = this.viewMode; + this.showMode(-1); + this.fill(); + if (oldViewMode === this.viewMode && this.autoclose) { + this.hide(); + } + } else { + this.fill(); + if (this.autoclose) { + this.hide(); + } + } + e.preventDefault(); + break; + case 9: // tab + this.hide(); + break; + } + if (dateChanged) { + var element; + if (this.isInput) { + element = this.element; + } else if (this.component) { + element = this.element.find('input'); + } + if (element) { + element.change(); + } + this.element.trigger({ + type: 'changeDate', + date: this.getDate() + }); + } + }, + + showMode: function (dir) { + if (dir) { + var newViewMode = Math.max(0, Math.min(DPGlobal.modes.length - 1, this.viewMode + dir)); + if (newViewMode >= this.minView && newViewMode <= this.maxView) { + this.element.trigger({ + type: 'changeMode', + date: this.viewDate, + oldViewMode: this.viewMode, + newViewMode: newViewMode + }); + + this.viewMode = newViewMode; + } + } + /* + vitalets: fixing bug of very special conditions: + jquery 1.7.1 + webkit + show inline datetimepicker in bootstrap popover. + Method show() does not set display css correctly and datetimepicker is not shown. + Changed to .css('display', 'block') solve the problem. + See https://github.com/vitalets/x-editable/issues/37 + + In jquery 1.7.2+ everything works fine. + */ + //this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + this.picker.find('>div').hide().filter('.datetimepicker-' + DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); + this.updateNavArrows(); + }, + + reset: function () { + this._setDate(null, 'date'); + }, + + convertViewModeText: function (viewMode) { + switch (viewMode) { + case 4: + return 'decade'; + case 3: + return 'year'; + case 2: + return 'month'; + case 1: + return 'day'; + case 0: + return 'hour'; + } + } + }; + + var old = $.fn.datetimepicker; + $.fn.datetimepicker = function (option) { + var args = Array.apply(null, arguments); + args.shift(); + var internal_return; + this.each(function () { + var $this = $(this), + data = $this.data('datetimepicker'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('datetimepicker', (data = new Datetimepicker(this, $.extend({}, $.fn.datetimepicker.defaults, options)))); + } + if (typeof option === 'string' && typeof data[option] === 'function') { + internal_return = data[option].apply(data, args); + if (internal_return !== undefined) { + return false; + } + } + }); + if (internal_return !== undefined) + return internal_return; + else + return this; + }; + + $.fn.datetimepicker.defaults = { + }; + $.fn.datetimepicker.Constructor = Datetimepicker; + var dates = $.fn.datetimepicker.dates = { + en: { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'], + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + meridiem: ['am', 'pm'], + suffix: ['st', 'nd', 'rd', 'th'], + today: 'Today', + clear: 'Clear' + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'minutes', + navFnc: 'Hours', + navStep: 1 + }, + { + clsName: 'hours', + navFnc: 'Date', + navStep: 1 + }, + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + } + ], + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] + }, + getDefaultFormat: function (type, field) { + if (type === 'standard') { + if (field === 'input') + return 'yyyy-mm-dd hh:ii'; + else + return 'yyyy-mm-dd hh:ii:ss'; + } else if (type === 'php') { + if (field === 'input') + return 'Y-m-d H:i'; + else + return 'Y-m-d H:i:s'; + } else { + throw new Error('Invalid format type.'); + } + }, + validParts: function (type) { + if (type === 'standard') { + return /t|hh?|HH?|p|P|z|Z|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g; + } else if (type === 'php') { + return /[dDjlNwzFmMnStyYaABgGhHis]/g; + } else { + throw new Error('Invalid format type.'); + } + }, + nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\rTZ]+/g, + parseFormat: function (format, type) { + // IE treats \0 as a string end in inputs (truncating the value), + // so it's a bad format delimiter, anyway + var separators = format.replace(this.validParts(type), '\0').split('\0'), + parts = format.match(this.validParts(type)); + if (!separators || !separators.length || !parts || parts.length === 0) { + throw new Error('Invalid date format.'); + } + return {separators: separators, parts: parts}; + }, + parseDate: function (date, format, language, type, timezone) { + if (date instanceof Date) { + var dateUTC = new Date(date.valueOf() - date.getTimezoneOffset() * 60000); + dateUTC.setMilliseconds(0); + return dateUTC; + } + if (/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(date)) { + format = this.parseFormat('yyyy-mm-dd', type); + } + if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(date)) { + format = this.parseFormat('yyyy-mm-dd hh:ii', type); + } + if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(date)) { + format = this.parseFormat('yyyy-mm-dd hh:ii:ss', type); + } + if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) { + var part_re = /([-+]\d+)([dmwy])/, + parts = date.match(/([-+]\d+)([dmwy])/g), + part, dir; + date = new Date(); + for (var i = 0; i < parts.length; i++) { + part = part_re.exec(parts[i]); + dir = parseInt(part[1]); + switch (part[2]) { + case 'd': + date.setUTCDate(date.getUTCDate() + dir); + break; + case 'm': + date = Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype, date, dir); + break; + case 'w': + date.setUTCDate(date.getUTCDate() + dir * 7); + break; + case 'y': + date = Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype, date, dir); + break; + } + } + return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), 0); + } + var parts = date && date.toString().match(this.nonpunctuation) || [], + date = new Date(0, 0, 0, 0, 0, 0, 0), + parsed = {}, + setters_order = ['hh', 'h', 'ii', 'i', 'ss', 's', 'yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'D', 'DD', 'd', 'dd', 'H', 'HH', 'p', 'P', 'z', 'Z'], + setters_map = { + hh: function (d, v) { + return d.setUTCHours(v); + }, + h: function (d, v) { + return d.setUTCHours(v); + }, + HH: function (d, v) { + return d.setUTCHours(v === 12 ? 0 : v); + }, + H: function (d, v) { + return d.setUTCHours(v === 12 ? 0 : v); + }, + ii: function (d, v) { + return d.setUTCMinutes(v); + }, + i: function (d, v) { + return d.setUTCMinutes(v); + }, + ss: function (d, v) { + return d.setUTCSeconds(v); + }, + s: function (d, v) { + return d.setUTCSeconds(v); + }, + yyyy: function (d, v) { + return d.setUTCFullYear(v); + }, + yy: function (d, v) { + return d.setUTCFullYear(2000 + v); + }, + m: function (d, v) { + v -= 1; + while (v < 0) v += 12; + v %= 12; + d.setUTCMonth(v); + while (d.getUTCMonth() !== v) + if (isNaN(d.getUTCMonth())) + return d; + else + d.setUTCDate(d.getUTCDate() - 1); + return d; + }, + d: function (d, v) { + return d.setUTCDate(v); + }, + p: function (d, v) { + return d.setUTCHours(v === 1 ? d.getUTCHours() + 12 : d.getUTCHours()); + }, + z: function () { + return timezone + } + }, + val, filtered, part; + setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; + setters_map['dd'] = setters_map['d']; + setters_map['P'] = setters_map['p']; + setters_map['Z'] = setters_map['z']; + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()); + if (parts.length === format.parts.length) { + for (var i = 0, cnt = format.parts.length; i < cnt; i++) { + val = parseInt(parts[i], 10); + part = format.parts[i]; + if (isNaN(val)) { + switch (part) { + case 'MM': + filtered = $(dates[language].months).filter(function () { + var m = this.slice(0, parts[i].length), + p = parts[i].slice(0, m.length); + return m === p; + }); + val = $.inArray(filtered[0], dates[language].months) + 1; + break; + case 'M': + filtered = $(dates[language].monthsShort).filter(function () { + var m = this.slice(0, parts[i].length), + p = parts[i].slice(0, m.length); + return m.toLowerCase() === p.toLowerCase(); + }); + val = $.inArray(filtered[0], dates[language].monthsShort) + 1; + break; + case 'p': + case 'P': + val = $.inArray(parts[i].toLowerCase(), dates[language].meridiem); + break; + case 'z': + case 'Z': + timezone; + break; + + } + } + parsed[part] = val; + } + for (var i = 0, s; i < setters_order.length; i++) { + s = setters_order[i]; + if (s in parsed && !isNaN(parsed[s])) + setters_map[s](date, parsed[s]) + } + } + return date; + }, + formatDate: function (date, format, language, type, timezone) { + if (date === null) { + return ''; + } + var val; + if (type === 'standard') { + val = { + t: date.getTime(), + // year + yy: date.getUTCFullYear().toString().substring(2), + yyyy: date.getUTCFullYear(), + // month + m: date.getUTCMonth() + 1, + M: dates[language].monthsShort[date.getUTCMonth()], + MM: dates[language].months[date.getUTCMonth()], + // day + d: date.getUTCDate(), + D: dates[language].daysShort[date.getUTCDay()], + DD: dates[language].days[date.getUTCDay()], + p: (dates[language].meridiem.length === 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''), + // hour + h: date.getUTCHours(), + // minute + i: date.getUTCMinutes(), + // second + s: date.getUTCSeconds(), + // timezone + z: timezone + }; + + if (dates[language].meridiem.length === 2) { + val.H = (val.h % 12 === 0 ? 12 : val.h % 12); + } + else { + val.H = val.h; + } + val.HH = (val.H < 10 ? '0' : '') + val.H; + val.P = val.p.toUpperCase(); + val.Z = val.z; + val.hh = (val.h < 10 ? '0' : '') + val.h; + val.ii = (val.i < 10 ? '0' : '') + val.i; + val.ss = (val.s < 10 ? '0' : '') + val.s; + val.dd = (val.d < 10 ? '0' : '') + val.d; + val.mm = (val.m < 10 ? '0' : '') + val.m; + } else if (type === 'php') { + // php format + val = { + // year + y: date.getUTCFullYear().toString().substring(2), + Y: date.getUTCFullYear(), + // month + F: dates[language].months[date.getUTCMonth()], + M: dates[language].monthsShort[date.getUTCMonth()], + n: date.getUTCMonth() + 1, + t: DPGlobal.getDaysInMonth(date.getUTCFullYear(), date.getUTCMonth()), + // day + j: date.getUTCDate(), + l: dates[language].days[date.getUTCDay()], + D: dates[language].daysShort[date.getUTCDay()], + w: date.getUTCDay(), // 0 -> 6 + N: (date.getUTCDay() === 0 ? 7 : date.getUTCDay()), // 1 -> 7 + S: (date.getUTCDate() % 10 <= dates[language].suffix.length ? dates[language].suffix[date.getUTCDate() % 10 - 1] : ''), + // hour + a: (dates[language].meridiem.length === 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''), + g: (date.getUTCHours() % 12 === 0 ? 12 : date.getUTCHours() % 12), + G: date.getUTCHours(), + // minute + i: date.getUTCMinutes(), + // second + s: date.getUTCSeconds() + }; + val.m = (val.n < 10 ? '0' : '') + val.n; + val.d = (val.j < 10 ? '0' : '') + val.j; + val.A = val.a.toString().toUpperCase(); + val.h = (val.g < 10 ? '0' : '') + val.g; + val.H = (val.G < 10 ? '0' : '') + val.G; + val.i = (val.i < 10 ? '0' : '') + val.i; + val.s = (val.s < 10 ? '0' : '') + val.s; + } else { + throw new Error('Invalid format type.'); + } + var date = [], + seps = $.extend([], format.separators); + for (var i = 0, cnt = format.parts.length; i < cnt; i++) { + if (seps.length) { + date.push(seps.shift()); + } + date.push(val[format.parts[i]]); + } + if (seps.length) { + date.push(seps.shift()); + } + return date.join(''); + }, + convertViewMode: function (viewMode) { + switch (viewMode) { + case 4: + case 'decade': + viewMode = 4; + break; + case 3: + case 'year': + viewMode = 3; + break; + case 2: + case 'month': + viewMode = 2; + break; + case 1: + case 'day': + viewMode = 1; + break; + case 0: + case 'hour': + viewMode = 0; + break; + } + + return viewMode; + }, + headTemplate: '' + + '' + + '' + + '' + + '' + + '' + + '', + headTemplateV3: '' + + '' + + ' ' + + '' + + ' ' + + '' + + '', + contTemplate: '', + footTemplate: '' + + '' + + '' + + '' + }; + DPGlobal.template = '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + '' + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
'; + DPGlobal.templateV3 = '
' + + '
' + + '' + + DPGlobal.headTemplateV3 + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplateV3 + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplateV3 + + '' + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplateV3 + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplateV3 + + DPGlobal.contTemplate + + DPGlobal.footTemplate + + '
' + + '
' + + '
'; + $.fn.datetimepicker.DPGlobal = DPGlobal; + + /* DATETIMEPICKER NO CONFLICT + * =================== */ + + $.fn.datetimepicker.noConflict = function () { + $.fn.datetimepicker = old; + return this; + }; + + /* DATETIMEPICKER DATA-API + * ================== */ + + $(document).on( + 'focus.datetimepicker.data-api click.datetimepicker.data-api', + '[data-provide="datetimepicker"]', + function (e) { + var $this = $(this); + if ($this.data('datetimepicker')) return; + e.preventDefault(); + // component click requires us to explicitly show it + $this.datetimepicker('show'); + } + ); + $(function () { + $('[data-provide="datetimepicker-inline"]').datetimepicker(); + }); + +})); diff --git a/web-application/todo_list/template/base.html b/web-application/todo_list/template/base.html index 2a7f80d..1402d19 100644 --- a/web-application/todo_list/template/base.html +++ b/web-application/todo_list/template/base.html @@ -7,6 +7,10 @@ {%block title%} {%endblock%} + + + + @@ -14,4 +18,7 @@ {%block body%} {%endblock%} + + {% block script %} + {% endblock %} diff --git a/web-application/todo_list/template/todo/add_todo.html b/web-application/todo_list/template/todo/add_todo.html index 27d19f1..fdab022 100644 --- a/web-application/todo_list/template/todo/add_todo.html +++ b/web-application/todo_list/template/todo/add_todo.html @@ -11,7 +11,30 @@

Add Todo

- +

+

+
+ -
-{%endblock%} + + {%endblock%} + + {% block script %} + + {% endblock %} diff --git a/web-application/todo_list/template/todo/index.html b/web-application/todo_list/template/todo/index.html index 60779c6..5737187 100644 --- a/web-application/todo_list/template/todo/index.html +++ b/web-application/todo_list/template/todo/index.html @@ -23,8 +23,8 @@

Todo List

{{todo.id}} {{todo.title}} - 2018 - 2019 + {{todo.created_time}} + {{todo.finished_time}} {{todo.status}} 新增 切换 修改 删除 搜索 diff --git a/web-application/todo_list/template/todo/update_todo.html b/web-application/todo_list/template/todo/update_todo.html index 1eb1904..8e59c35 100644 --- a/web-application/todo_list/template/todo/update_todo.html +++ b/web-application/todo_list/template/todo/update_todo.html @@ -9,9 +9,11 @@

Update Todo

- +
+

+

diff --git a/web-application/todo_list/todo.db b/web-application/todo_list/todo.db index 9182078acf223abcb188ba45876d7577e2b65220..25c7d4ebe905f4421abd7584c5bbe4c5b55c7b7b 100644 GIT binary patch delta 352 zcmZojXh@hK%_ucd#+gxSW5ObSzD5RSzLyOAW_&OC_wc>kEGTf3uil%DjX|H&(Xk{y zC12tB-igmw&wRS4;c5RwBLhPVT|)z1BMSv1Ln{LVAks4c1GtQ(f}t^rj3+A_gEohw z5!WJ|s1_lP}iG}7NPV8(9vOqI4)1S?0c)Dj7 zl3}>qh2df@{+kTU{OcL`Kl88WKgxe}v!KF!emzlUeMSs#vk5b6Gorbl73dbJiH>5t MJj}9;Fn6#606gDp0{{R3 delta 176 zcmZojXh@hK%_ulg#+gxYW5ObSp7jij{EZC!jUc#LP{Ea-h5ssp-o!#JBOPWo22~D6 zhKx*wCwmt>UAp(_)Gi|fLknF)16?B%1tViCATl-9Gd4D~G&f{mU=0!^I9Ke0j9oc}X}08j}W2r#QMA{)#Mlo5l=!WjUXK`TrE diff --git a/web-application/todo_list/todo_web.py b/web-application/todo_list/todo_web.py index 4fd70d9..7e85170 100644 --- a/web-application/todo_list/todo_web.py +++ b/web-application/todo_list/todo_web.py @@ -42,7 +42,7 @@ def before_first_do(): @app.route('/') def index(): - todos = Todo.query.all() + todos = Todo.query.order_by(db.desc(Todo.status)).all() time = datetime.now() return render_template('todo/index.html', time=time, todos=todos) @@ -54,6 +54,12 @@ def add_todo(): elif request.method == 'POST': title = request.form.get('title') todo = Todo(title=title) + # 2018-10-28 11:00:00 + todo.created_time = datetime.strptime( + request.form.get('created_time', None), '%Y-%m-%d %H:%M:%S') + todo.finished_time = datetime.strptime( + request.form.get('finished_time', None), '%Y-%m-%d %H:%M:%S') + todo.status = False db.session.add(todo) db.session.commit() return redirect(url_for('index')) @@ -87,12 +93,19 @@ def delete_todo(): @app.route('/update_todo', methods=['GET', 'POST']) def update_todo(): if request.method == 'GET': - return render_template('todo/update_todo.html') + id = request.args.get('id', None) + if id: + todo = Todo.query.get_or_404(id) + return render_template('todo/update_todo.html', todo=todo) elif request.method == 'POST': id = request.form.get('id') title = request.form.get('title') todo = Todo.query.get_or_404(id) todo.title = title + todo.created_time = datetime.strptime( + request.form.get('created_time', None), '%Y-%m-%d %H:%M:%S') + todo.finished_time = datetime.strptime( + request.form.get('finished_time', None), '%Y-%m-%d %H:%M:%S') db.session.add(todo) db.session.commit() return redirect(url_for('index')) From 7144dbce4a3c43f61997b55d406c07958f70b1b0 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Sun, 28 Oct 2018 22:00:28 +0800 Subject: [PATCH 09/16] update program lists --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 63b9cf7..082b585 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ * 网站定时检查器——每隔一段时间或者在预定的时间尝试连接某个网站或者服务器,来检查它是否可以连上,如果连不上了会通过邮件或者桌面通知来告知你。 * 小型网页服务器——简易版的网页服务器,可以存放包含Javascript和其它形式代码的HTML文件。复杂一点的话可以尝试流媒体视频、创建一种服务器端语言或者其它类型的流媒体。 * 网络蜘蛛——一个可以自动执行网页上各种任务的程序,任务包括网站检查、页面抓取、数据摘要以及网络邮务。 +* 爬虫, 可以翻译中文, 英文, 句子, 困难点可以整合网上的词典. ### 类 From ff55be3e4582479605baa14c732f19aade154ffc Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Thu, 1 Nov 2018 22:14:17 +0800 Subject: [PATCH 10/16] update password mail --- README.md | 5 +- text-operation/password_mail/.flaskenv | 2 + text-operation/password_mail/.idea/misc.xml | 7 + .../password_mail/.idea/modules.xml | 8 + .../password_mail/.idea/password_mail.iml | 22 ++ text-operation/password_mail/.idea/vcs.xml | 6 + .../password_mail/.idea/workspace.xml | 236 ++++++++++++++++++ text-operation/password_mail/Pipfile | 13 + text-operation/password_mail/Pipfile.lock | 73 ++++++ text-operation/password_mail/password_mail.py | 46 ++++ .../password_mail/templates/index.html | 25 ++ .../password_mail/test_password_mail.py | 6 + web-application/todo_list/.flaskenv | 2 + web-application/todo_list/Pipfile | 1 + web-application/todo_list/Pipfile.lock | 18 +- .../{template => templates}/base.html | 0 .../todo/add_todo.html | 0 .../{template => templates}/todo/index.html | 0 .../todo/search_todo.html | 0 .../todo/update_todo.html | 0 web-application/todo_list/test_todo_web.py | 14 ++ web-application/todo_list/todo_web.py | 6 +- 22 files changed, 477 insertions(+), 13 deletions(-) create mode 100644 text-operation/password_mail/.flaskenv create mode 100644 text-operation/password_mail/.idea/misc.xml create mode 100644 text-operation/password_mail/.idea/modules.xml create mode 100644 text-operation/password_mail/.idea/password_mail.iml create mode 100644 text-operation/password_mail/.idea/vcs.xml create mode 100644 text-operation/password_mail/.idea/workspace.xml create mode 100644 text-operation/password_mail/Pipfile create mode 100644 text-operation/password_mail/Pipfile.lock create mode 100644 text-operation/password_mail/password_mail.py create mode 100644 text-operation/password_mail/templates/index.html create mode 100644 text-operation/password_mail/test_password_mail.py create mode 100644 web-application/todo_list/.flaskenv rename web-application/todo_list/{template => templates}/base.html (100%) rename web-application/todo_list/{template => templates}/todo/add_todo.html (100%) rename web-application/todo_list/{template => templates}/todo/index.html (100%) rename web-application/todo_list/{template => templates}/todo/search_todo.html (100%) rename web-application/todo_list/{template => templates}/todo/update_todo.html (100%) create mode 100644 web-application/todo_list/test_todo_web.py diff --git a/README.md b/README.md index 082b585..7bd06e6 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,10 @@ ### 文本操作 * ~~逆转字符串——输入一个字符串,将其逆转并输出。~~ -* 拉丁猪文字游戏——这是一个英语语言游戏。基本规则是将一个英语单词的第一个辅音音素的字母移动到词尾并且加上后缀-ay(譬如“banana”会变成“anana-bay”)。可以在维基百科上了解更多内容。 * ~~统计元音字母——输入一个字符串,统计处其中元音字母的数量。更复杂点的话统计出每个元音字母的数量。~~ * ~~判断是否为回文——判断用户输入的字符串是否为回文。回文是指正反拼写形式都是一样的词,譬如“racecar”。~~ * 统计字符串中的单词数目——统计字符串中单词的数目,更复杂的话从一个文本中读出字符串并生成单词数目统计结果。 -* 文本编辑器——记事本类型的应用,可以打开、编辑、保存文本文档。可以增加单词高亮和其它的一些特性。 +* ~~文本编辑器——记事本类型的应用,可以打开、编辑、保存文本文档~~, 可以增加单词高亮和其它的一些特性。 * RSS源创建器——可以从其它来源读取文本并将其以RSS或者Atom的格式发布出去。 * 实时股价——可以查询股票当前价格。用户可以设定数据刷新频率,程序会用绿色和红色的箭头表示股价走势。 * 访客留言簿/日志——允许人们添加评论或者日记,可以设置开启/关闭评论,并且可以记录下每一条目的时间。也可以做成喊话器。 @@ -42,7 +41,7 @@ * 网站定时检查器——每隔一段时间或者在预定的时间尝试连接某个网站或者服务器,来检查它是否可以连上,如果连不上了会通过邮件或者桌面通知来告知你。 * 小型网页服务器——简易版的网页服务器,可以存放包含Javascript和其它形式代码的HTML文件。复杂一点的话可以尝试流媒体视频、创建一种服务器端语言或者其它类型的流媒体。 * 网络蜘蛛——一个可以自动执行网页上各种任务的程序,任务包括网站检查、页面抓取、数据摘要以及网络邮务。 -* 爬虫, 可以翻译中文, 英文, 句子, 困难点可以整合网上的词典. +* 爬虫命令行翻译工具--可以翻译中文, 英文, 句子, 困难点可以整合网上的词典. ### 类 diff --git a/text-operation/password_mail/.flaskenv b/text-operation/password_mail/.flaskenv new file mode 100644 index 0000000..99afacb --- /dev/null +++ b/text-operation/password_mail/.flaskenv @@ -0,0 +1,2 @@ +FLASK_APP=password_mail:app +FLASK_ENV = development diff --git a/text-operation/password_mail/.idea/misc.xml b/text-operation/password_mail/.idea/misc.xml new file mode 100644 index 0000000..a6ebb1f --- /dev/null +++ b/text-operation/password_mail/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/text-operation/password_mail/.idea/modules.xml b/text-operation/password_mail/.idea/modules.xml new file mode 100644 index 0000000..eeeb633 --- /dev/null +++ b/text-operation/password_mail/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/text-operation/password_mail/.idea/password_mail.iml b/text-operation/password_mail/.idea/password_mail.iml new file mode 100644 index 0000000..7f50591 --- /dev/null +++ b/text-operation/password_mail/.idea/password_mail.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/text-operation/password_mail/.idea/vcs.xml b/text-operation/password_mail/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/text-operation/password_mail/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/text-operation/password_mail/.idea/workspace.xml b/text-operation/password_mail/.idea/workspace.xml new file mode 100644 index 0000000..9c610ff --- /dev/null +++ b/text-operation/password_mail/.idea/workspace.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + +
+ + + we use base64! +
+ + + + + diff --git a/text-operation/password_mail/test_password_mail.py b/text-operation/password_mail/test_password_mail.py new file mode 100644 index 0000000..947a1f9 --- /dev/null +++ b/text-operation/password_mail/test_password_mail.py @@ -0,0 +1,6 @@ +from password_mail import app + + +def test_password_mail(): + client = app.test_client() + pass diff --git a/web-application/todo_list/.flaskenv b/web-application/todo_list/.flaskenv new file mode 100644 index 0000000..1f2c262 --- /dev/null +++ b/web-application/todo_list/.flaskenv @@ -0,0 +1,2 @@ +FLASK_APP=app +FLASK_ENV = development diff --git a/web-application/todo_list/Pipfile b/web-application/todo_list/Pipfile index 84821a1..618c90c 100644 --- a/web-application/todo_list/Pipfile +++ b/web-application/todo_list/Pipfile @@ -8,6 +8,7 @@ flask = "*" flask-sqlalchemy = "*" gevent = "*" gunicorn = "*" +python-dotenv = "*" [dev-packages] diff --git a/web-application/todo_list/Pipfile.lock b/web-application/todo_list/Pipfile.lock index 590a9d4..be09151 100644 --- a/web-application/todo_list/Pipfile.lock +++ b/web-application/todo_list/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1c17f06b505e80646d239b8c3bbd25add0287e3a77ffff19cf3809a808f3ec44" + "sha256": "79d55fa6948e8535cf69ff08d638f5182529ff584144979910224cbcfc8d281c" }, "pipfile-spec": 6, "requires": { @@ -104,11 +104,11 @@ }, "itsdangerous": { "hashes": [ - "sha256:a7de3201740a857380421ef286166134e10fe58846bcefbc9d6424a69a0b99ec", - "sha256:aca4fc561b7671115a2156f625f2eaa5e0e3527e0adf2870340e7968c0a81f85" + "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", + "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*'", - "version": "==1.0.0" + "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.2.*'", + "version": "==1.1.0" }, "jinja2": { "hashes": [ @@ -123,6 +123,14 @@ ], "version": "==1.0" }, + "python-dotenv": { + "hashes": [ + "sha256:122290a38ece9fe4f162dc7c95cae3357b983505830a154d3c98ef7f6c6cea77", + "sha256:4a205787bc829233de2a823aa328e44fd9996fedb954989a21f1fc67c13d7a77" + ], + "index": "pypi", + "version": "==0.9.1" + }, "sqlalchemy": { "hashes": [ "sha256:c5951d9ef1d5404ed04bae5a16b60a0779087378928f997a294d1229c6ca4d3e" diff --git a/web-application/todo_list/template/base.html b/web-application/todo_list/templates/base.html similarity index 100% rename from web-application/todo_list/template/base.html rename to web-application/todo_list/templates/base.html diff --git a/web-application/todo_list/template/todo/add_todo.html b/web-application/todo_list/templates/todo/add_todo.html similarity index 100% rename from web-application/todo_list/template/todo/add_todo.html rename to web-application/todo_list/templates/todo/add_todo.html diff --git a/web-application/todo_list/template/todo/index.html b/web-application/todo_list/templates/todo/index.html similarity index 100% rename from web-application/todo_list/template/todo/index.html rename to web-application/todo_list/templates/todo/index.html diff --git a/web-application/todo_list/template/todo/search_todo.html b/web-application/todo_list/templates/todo/search_todo.html similarity index 100% rename from web-application/todo_list/template/todo/search_todo.html rename to web-application/todo_list/templates/todo/search_todo.html diff --git a/web-application/todo_list/template/todo/update_todo.html b/web-application/todo_list/templates/todo/update_todo.html similarity index 100% rename from web-application/todo_list/template/todo/update_todo.html rename to web-application/todo_list/templates/todo/update_todo.html diff --git a/web-application/todo_list/test_todo_web.py b/web-application/todo_list/test_todo_web.py new file mode 100644 index 0000000..96785eb --- /dev/null +++ b/web-application/todo_list/test_todo_web.py @@ -0,0 +1,14 @@ +from todo_web import app +import pytest + + +@pytest.fixture +def test_flask_app(): + pass + + +def test_root_api(): + client = app.test_client() + response = client.get('/') + assert response.status_code == 200 + assert 'todo 小网站'.encode() in response.get_data() diff --git a/web-application/todo_list/todo_web.py b/web-application/todo_list/todo_web.py index 7e85170..a54a7f3 100644 --- a/web-application/todo_list/todo_web.py +++ b/web-application/todo_list/todo_web.py @@ -3,7 +3,7 @@ from flask import Flask, abort, redirect, render_template, request, url_for from flask_sqlalchemy import SQLAlchemy -app = Flask(__name__, template_folder='./template', static_folder='./static') +app = Flask(__name__, template_folder='./templates', static_folder='./static') # config sqlite config app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db' @@ -130,7 +130,3 @@ def search_todo(): @app.route('/test') def test(): return render_template('todo/test.html') - - -if __name__ == "__main__": - app.run(debug=True) From 658d61c85d126e8e89bc74d8ec3257d2f3494639 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Fri, 2 Nov 2018 13:22:37 +0800 Subject: [PATCH 11/16] finish password mail --- README.md | 2 +- .../password_mail/.idea/workspace.xml | 294 +++++++++++++++--- text-operation/password_mail/Pipfile | 1 + text-operation/password_mail/Pipfile.lock | 17 +- text-operation/password_mail/password_mail.py | 10 +- .../password_mail/test_password_mail.py | 16 +- 6 files changed, 283 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 7bd06e6..6774eda 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ * 访客留言簿/日志——允许人们添加评论或者日记,可以设置开启/关闭评论,并且可以记录下每一条目的时间。也可以做成喊话器。 * 新闻和比分播报器——一个桌面应用,可以从网上收集新闻和比赛分数,将结果在屏幕上滚动播出。 * 占星罗盘——用占星术来预测每天的运程。 -* 密码短信——可以将数据加密解密,并能将其发送给朋友。 +* ~~密码短信——可以将数据加密解密,并能将其发送给朋友。~~ * 帮你挑礼物——输入一堆你可能会送的礼物,当有人过生日时,该程序会随机选择一样礼物。也可以加上一个额外功能,可以告知哪里可以弄到这个礼物。 * HTML生成器——将 TEXT 文档转换成HTML文件,对制作网页HTML文档很有用。 * CD-Key生成器——利用某种算法生成一个唯一的key。软件开发者可以用它来作为软件的激活器。 diff --git a/text-operation/password_mail/.idea/workspace.xml b/text-operation/password_mail/.idea/workspace.xml index 9c610ff..c569798 100644 --- a/text-operation/password_mail/.idea/workspace.xml +++ b/text-operation/password_mail/.idea/workspace.xml @@ -2,16 +2,11 @@ - - - - - - - - - - + + + + + - + + - + + + - + + + - + + + - + + + + + + - + + + + + - - - - - - + - - + + + + + + + + + + + - - + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + @@ -122,6 +193,11 @@ + + + + + @@ -18,7 +18,7 @@ we use base64! - + From 2119e733a221602f9da9782a283daee525ea3ba6 Mon Sep 17 00:00:00 2001 From: buglan <1831353087@qq.com> Date: Fri, 30 Nov 2018 10:12:38 +0800 Subject: [PATCH 13/16] delete .idea and update .gitignore --- .gitignore | 7 + text-operation/password_mail/.idea/misc.xml | 7 - .../password_mail/.idea/modules.xml | 8 - .../password_mail/.idea/password_mail.iml | 22 - text-operation/password_mail/.idea/vcs.xml | 6 - .../password_mail/.idea/workspace.xml | 435 ------------------ 6 files changed, 7 insertions(+), 478 deletions(-) delete mode 100644 text-operation/password_mail/.idea/misc.xml delete mode 100644 text-operation/password_mail/.idea/modules.xml delete mode 100644 text-operation/password_mail/.idea/password_mail.iml delete mode 100644 text-operation/password_mail/.idea/vcs.xml delete mode 100644 text-operation/password_mail/.idea/workspace.xml diff --git a/.gitignore b/.gitignore index 28c8676..8b6a318 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,11 @@ +# python __pycache__/ *.py[cod] .pytest_cache/ .mypy_cache/ + +# visual stdio code +.vscode/ + +# pycharm +.idea/ \ No newline at end of file diff --git a/text-operation/password_mail/.idea/misc.xml b/text-operation/password_mail/.idea/misc.xml deleted file mode 100644 index a6ebb1f..0000000 --- a/text-operation/password_mail/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/text-operation/password_mail/.idea/modules.xml b/text-operation/password_mail/.idea/modules.xml deleted file mode 100644 index eeeb633..0000000 --- a/text-operation/password_mail/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/text-operation/password_mail/.idea/password_mail.iml b/text-operation/password_mail/.idea/password_mail.iml deleted file mode 100644 index 7f50591..0000000 --- a/text-operation/password_mail/.idea/password_mail.iml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/text-operation/password_mail/.idea/vcs.xml b/text-operation/password_mail/.idea/vcs.xml deleted file mode 100644 index b2bdec2..0000000 --- a/text-operation/password_mail/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/text-operation/password_mail/.idea/workspace.xml b/text-operation/password_mail/.idea/workspace.xml deleted file mode 100644 index e72473a..0000000 --- a/text-operation/password_mail/.idea/workspace.xml +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - k - - - - - - - - - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - -