Список веб-приложений


Я лично считаю, что это полезно, чтобы увидеть, какие аспекты программы уже реализованы и какие функции мне нужно добавить. Просто для удовольствия, я решил написать программу для этого. Это первая программа, за которую я пытался написать код в чистом виде. Извините за длинный, перемудрил код.

Кстати, программа сохраняет/загружает данные странные и неэффективные, в основном, потому что я не знаю лучшего способа.

Программа HTML и JavaScript общаясь на Питон веб-сервер. Я также вела программу на сервер, чтобы сделать крест происхождения вещи проще. К сожалению все имена жестко прописаны в программе.

webserver.py:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer

startData = "###DATAGOESHERE###"
endData = "###ENDDATAGOESHERE###"

def readFile(fileName):
    with open(fileName,'r') as f:
        data = f.read()
        f.close()
    return data

def replaceWithData(string, data):
    data = data.strip()
    if data.strip() == "":
        return string.replace(startData, "").replace(endData, "")
    else:
        start = string.find(startData)
        end = string.find(endData)+len(endData)
        string = string[:start]+data+string[end:]
        return string

def writeFile(fileName, data):
    with open(fileName,'w') as f:
        f.write(data)
        f.close()

def serveStaticApp(request, url):
    data = readFile('data.html')
    html = readFile('main.html')
    html = replaceWithData(html, data)
    request.wfile.write(html)

def serverStaticFile(request, url):
    data = readFile(url)
    request.wfile.write(data)

def saveData(request, url):
    length = int(request.headers.getheader('content-length'))
    data = request.rfile.read(length).strip()
    writeFile('data.html', data)

funcMap = {
    "app": serveStaticApp,
    "main.js":serverStaticFile,
    "save": saveData,
    "main.css": serverStaticFile,
}

def handleRequest(request):
    request._set_headers()
    for i in funcMap.keys():
        if request.path[-len(i):] == i:
            funcMap[i](request, i)
            return
    request.wfile.write("<html><body><h1>REQUEST!</h1></body></html>")

class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):
        handleRequest(self)

    def do_HEAD(self):
        self._set_headers()

    def do_POST(self):
        handleRequest(self)


def run(server_class=HTTPServer, handler_class=S, port=8080):
    server_address = ('localhost', port)
    httpd = server_class(server_address, handler_class)
    print 'Starting...'
    httpd.serve_forever()

if __name__ == "__main__":
    from sys import argv

    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()

main.html

<!DOCTYPE>
<html>
<head>
    <link rel="stylesheet" href="main.css" type="text/css">
</head>
<body>
    <div>
        <span id="not-implemented-label">Not Implemented:</span>
        <span id="implemented-label">Implemented:</span>
    </div>
    <span id="save">
        ###DATAGOESHERE###
        <select id="not-implemented-select" size="2" multiple="true"></select>
        <span id="controls">
            <input type="button" value="<-" id="left-arrow-button">
            <input type="button" value="LOAD" id="load-button">
            <input type="button" value="->" id="right-arrow-button"><br>
            <input type="button" value="DELETE" id="delete-button">
        </span>
        <select id="implemented-select" size="2" multiple="true"></select>
        ###ENDDATAGOESHERE###
    </span>
    <br>
    <br>
    <input type="text" id="title-input" placeholder="Title"><br>
    <textarea id="description-input" placeholder="Description"></textarea>
    <span id="save-controls">
        <input type="button" value="SAVE OVER" id="save-over-button"><br>
        <input type="button" value="SAVE NEW" id="save-new-button"><br>
        <input type="button" value="CLEAR" id="clear-button">
    </span>
    <script src="functions.js"></script>
    <script src="main.js"></script>
</body>
</html>

главная.УСБ

select{
    width:40vw;
    height:60vh;

}
textarea{
    width:80vw;
    height:30vh;
}
#title-input{
    width:80vw;
}
#controls{
    display:inline-block;
    width:8em;
    text-align: center;
}
#save-controls{
    display:inline-block;
}
#not-implemented-label{
    display:inline-block;
    width:calc(40vw + 8em);
}
.description{
    display:none;
}

main.js

"use strict";
var mostRecentlySelectedOptions = [];
var allowTextOverrride = true;
var saveServerURL = "/save"

var cachedElements = {};
function gebi(id){
    var cachedElement = cachedElements[id];
    if(cachedElement === undefined){
        cachedElement = document.getElementById(id);
        cachedElements[id] = cachedElement;
        return cachedElement;
    }else{
        return cachedElement;
    }
}

function slice(collection){
    return [].slice.call(collection);
}

function moveOptions(options, toSelect){
    options = options.slice();
    for(var i = 0; i < options.length; i++){
        toSelect.appendChild(options[i]);
    }
    saveToServer();
}

function setInputs(title, description){
    allowTextOverrride = true;
    gebi("title-input").value = title;
    gebi("description-input").value = description;
}

function getInputs(){
    return {
        "title": gebi("title-input").value, 
        "description": gebi("description-input").value
    };
}

function getSafeInputs(){
    var inputs = getInputs();
    if(inputs.title.trim() == ""){
        inputs.title = "<untitled>";
    }
    inputs.title = inputs.title.trim();
    inputs.description = inputs.description.trim();
    return inputs;
}

function clearInputs(){
    setInputs("", "");
}

function moveSelectedOptions(toSelect){
    moveOptions(mostRecentlySelectedOptions, toSelect);
}

function onSelectionChange(target){
    mostRecentlySelectedOptions = slice(target.selectedOptions);
    if(allowTextOverrride){
        loadSelectedOption();
    }
}

function deselectAllInSelect(selectElement){
    var selected = selectElement.selectedOptions;
    for(var i = 0; i < selected.length; i++){
        selected[i].selected = false;
    }
}

function saveText(){
    allowTextOverrride = true;
    saveToServer();
}

function saveToServer(){
    var dataToSave = gebi("save").innerHTML;
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", saveServerURL, true);
    xhttp.setRequestHeader("Content-type", "text/plain");
    xhttp.send(dataToSave);
}

function removeOptions(options){
    options = options.slice();
    for(var i = 0; i < options.length; i++){
        options[i].parentNode.removeChild(options[i]);
    }
    saveToServer();
}

function removeSelectedOptions(){
    removeOptions(mostRecentlySelectedOptions);
}

function setOptionData(option, title, description){
    option.text = title;
    option.setAttribute("data-description", description);
}

function getOptionData(option){
    return {
        "title": option.text, 
        "description": option.getAttribute("data-description")
    };
}

function createOption(title, description){
    var option = document.createElement("option");
    setOptionData(option, title, description);
    return option;
}

function addOption(title, description, parentSelect){
    var option = createOption(title, description);
    parentSelect.add(option);
    deselectAllInSelect(parentSelect);
    option.selected = true;
}

function saveNew(){
    var inputData = getSafeInputs();
    var parentSelect = gebi("not-implemented-select");
    addOption(inputData.title, inputData.description, parentSelect);
    saveText();
}

function loadSelectedOption(){
    if(mostRecentlySelectedOptions.length == 1){
        var selectedOption = mostRecentlySelectedOptions[0];
        var data = getOptionData(selectedOption);
        setInputs(data.title, data.description);
    }
}

function saveOverwrite(){
    if(mostRecentlySelectedOptions.length == 1){
        var selectedOption = mostRecentlySelectedOptions[0];
        var inputData = getSafeInputs();
        setOptionData(selectedOption, inputData.title, inputData.description);
        saveText();
    }else{
        saveNew();
    }
}

function addEventListeners(){
    var notImplementedSelect = gebi("not-implemented-select");
    var implementedSelect = gebi("implemented-select");

    gebi("right-arrow-button").addEventListener("click", function(){
        moveSelectedOptions(implementedSelect);
    });

    gebi("left-arrow-button").addEventListener("click", function(){
        moveSelectedOptions(notImplementedSelect);
    });

    gebi("load-button").addEventListener("click", function(){
        loadSelectedOption();
        allowTextOverrride = false;
    });

    gebi("delete-button").addEventListener("click", function(){
        removeSelectedOptions();
    });

    gebi("save-over-button").addEventListener("click", function(){
        saveOverwrite();
    });

    gebi("save-new-button").addEventListener("click", function(){
        saveNew();
    });

    gebi("clear-button").addEventListener("click", function(){
        clearInputs();
    });

    implementedSelect.addEventListener("change", function(event){
        onSelectionChange(event.target);
    });

    implementedSelect.addEventListener("focus", function(event){
        onSelectionChange(event.target);
    });

    notImplementedSelect.addEventListener("change", function(event){
        onSelectionChange(event.target);
    });

    notImplementedSelect.addEventListener("focus", function(event){
        onSelectionChange(event.target);
    });

    gebi("title-input").addEventListener("keypress", function(){
        allowTextOverrride = false;
    });

    gebi("description-input").addEventListener("keypress", function(){
        allowTextOverrride = false;
    });

    window.addEventListener("beforeunload", function(){
        //alert();
    });
}

addEventListeners();

Чтобы запустить его, поместите все файлы в тот же каталог и запустить файл python. Вам также нужно пустой файл с названием data.html в том же каталоге. Тогда посетите http://localhost:8080/app чтобы получить доступ к приложению.

Вы можете поместить небольшой заголовок для задач и более подробное описание задания и нажмите Сохранить новые. Сохранить за сохранит за все, что вы выбрали. Две кнопки со стрелками переместите задач между колоннами. Важно отметить, что веб-сервер не должен быть запущен через интернет.

Я особенно интересные в следующем:

  • Мои переменные/функции по имени?
  • Мои функции делает слишком много или слишком мало?
  • Бывали ли случаи, что вы можете получить неожиданное поведение?
  • Вы чувствуете, что код-это легко растяжимый/ремонтопригодны?
  • Что я могу сделать о длинном списке addEventListenerы?


234
5
задан 2 марта 2018 в 08:03 Источник Поделиться
Комментарии