Html5 Web App 示例TaskAtHand

1.项目结构

     

2.源码分析

taskAtHand.html

<!DOCTYPE html>
<html>
<head>
    <title>Task@Hand</title>
    <link href="taskAtHand.css" rel="StyleSheet" type="text/css" />
    <link id="theme-style" href="themes/blue.css" rel="StyleSheet" type="text/css" />
    <script src="lib/jquery-1.10.2.js" type="text/javascript"></script>
    <script src="appStorage.js" type="text/javascript"></script>
    <script src="taskAtHand.js" type="text/javascript"></script>
</head>
<body>
    <div id="app">
        <header>Task@Hand</header>
        <div id="toolbar">
            <label for="theme">Theme</label>
            <select id="theme" title="Select theme">
                <option value="blue">Blue</option>
                <option value="green">Green</option>
                <option value="brown">Brown</option>
                <option value="red">Red</option>
            </select>
        </div>
        <div id="main">
            <div id="add-task">
                <label for="new-task-name">Add a task</label>
                <input type="text" id="new-task-name" title="Enter a task name" placeholder="Enter a task name" autofocus/>
            </div>
            <ul id="task-list">
            </ul>
        </div>
        <footer>
        </footer>
    </div>
    <div id="templates" class="hidden">
        <ul id="task-template">
            <li class="task">
                <button class="toggle-details">+</button>
                <span class="task-name"></span>
                <input type="text" class="task-name hidden"/>
                <div class="tools">
                    <button class="delete" title="Delete">X</button>
                    <button class="move-up" title="Up">^</button>
                    <button class="move-down" title="Down">v</button>
                </div>
                <div class="details">
                    <label>Start date:</label>
                    <input type="date"/><br/>
                    <label>Due date:</label>
                    <input type="date"/><br/>
                    <label>Status:</label>
                    <select>
                        <option value="0">None</option>
                        <option value="1">Not Started</option>
                        <option value="2">Started</option>
                        <option value="3">Completed</option>
                    </select><br/>
                    <label>Priority:</label>
                    <select>
                        <option value="0">None</option>
                        <option value="1">Low</option>
                        <option value="2">Normal</option>
                        <option value="3">High</option>
                    </select><br/>
                    <label>%&nbsp;Complete:</label>
                    <input type="number" min="0" max="100" step="10" value="0"/>
                </div>
            </li>
        </ul>
    </div>
</body>
</html>

taskAtHand.js

"use strict";

function TaskAtHandApp()
{
    var version = "v3.1",
        appStorage = new AppStorage("taskAtHand");
        
    function setStatus (message) 
    {
        $("app>footer").text(message);
    }

    function saveTaskList()
    {
        var tasks = [];
        $("#task-list .task span.task-name").each(function() {
            tasks.push($(this).text())
        });
        appStorage.setValue("taskList", tasks);
    }
    
    function addTask()
    {
        var taskName = $("#new-task-name").val();
        if (taskName)
        {
            addTaskElement(taskName);
            // Reset the field
            $("#new-task-name").val("").focus();
            saveTaskList();
        }
    }

    function addTaskElement(taskName)
    {
        var $task = $("#task-template .task").clone();
        $("span.task-name", $task).text(taskName);

        $("#task-list").append($task);
        
        // Task events
        $task.click(function() { onSelectTask($task); });
        
        // Button events
        $("button.delete", $task).click(function() { removeTask($task); });
        $("button.move-up", $task).click(function() { moveTask($task, true); });
        $("button.move-down", $task).click(function() { moveTask($task, false); });
        $("button.toggle-details", $task).click(function() { toggleDetails($task); });

        // Task name events
        $("span.task-name", $task).click(function() { onEditTaskName($(this)); });
        $("input.task-name", $task).change(function() { onChangeTaskName($(this)); })
            .blur(function() { $(this).hide().siblings("span.task-name").show(); });
    }

    //to toggle visibility of details
    function toggleDetails($task)
    {
        $(".details", $task).slideToggle();
        $("button.toggle-details", $task).toggleClass("expanded");
    }
    
    function removeTask($task)
    {
        $task.remove();
        saveTaskList();
    }
    
    function moveTask($task, moveUp)
    {
        if (moveUp)
        {
            $task.insertBefore($task.prev());
        }
        else
        {
            $task.insertAfter($task.next());
        }
        saveTaskList();
    }

    function onSelectTask($task)
    {
        if ($task)
        {
            // Unselect other tasks
            $task.siblings(".selected").removeClass("selected");
            // Select this task
            $task.addClass("selected");
        }
    }

    function onEditTaskName($span)
    {
        $span.hide()
             .siblings("input.task-name").val($span.text()).show().focus();
    }

    function onChangeTaskName($input)
    {
        $input.hide();
        var $span = $input.siblings("span.task-name");
        if ($input.val())
        {
            $span.text($input.val());
            saveTaskList();
        }
        $span.show();
    }
    
    function loadTaskList()
    {
        var tasks = appStorage.getValue("taskList");
        if (tasks)
        {
            for (var i in tasks)
            {
                addTaskElement(tasks[i]);
            }
        }
    }
    
    function onChangeTheme()
    {
        var theme = $("#theme>option").filter(":selected").val();
        setTheme(theme);
        appStorage.setValue("theme", theme);
    }
    
    /*gets the <link id="theme-style"> element and changes its href
    attribute to the new stylesheet's URL */
    /*when page loads, new stylesheet loads and apply its styles over 
    the existing ones*/
    function setTheme(theme)
    {
        $("#theme-style").attr("href", "themes/" + theme + ".css");
    }
    
    /*gets theme name from localStorage*/
    function loadTheme()
    {
        var theme = appStorage.getValue("theme");
        if (theme)
        {
            setTheme(theme);
            $("#theme>option[value=" + theme + "]").attr("selected","selected");
        }
    }
    
    this.start = function()
    {
        $("#new-task-name").keypress(function(e)
        {
            if (e.which == 13) // Enter key
            {
                addTask();
                return false;
            }
        })
        .focus();
        
        loadTheme();
        $("#theme").change(onChangeTheme);
        
        $("#app>header").append(version);
        
        loadTaskList();
        setStatus("ready");
    };
}

$(function()
{
    window.app = new TaskAtHandApp();
    window.app.start();
});

taskAthand.css

body
{
    font: 1em Verdana, Geneva, sans-serif;
    padding: 0;
    margin: 5px;
    color: Black;
    background-color: WhiteSmoke;
}
div
{
    padding: 0;
    margin: 0;
}
button
{
    cursor: pointer;
}
.hidden
{
    display: none;
}


/* The App */

#app
{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    overflow: auto;

    margin: 4px;
    background-color: #bbc;
    background: -webkit-linear-gradient(top, #bbc, #558);
    background: -moz-linear-gradient(top, #bbc, #558);
    background: -ms-linear-gradient(top, #bbc, #558);
    background: linear-gradient(top, #bbc, #558);
}

#app>header
{
    padding: 0 0.5em;
    font-size: 1.5em;
    color: WhiteSmoke;
    background-color: #006;
    box-shadow: 2px 3px 3px rgba(0, 0, 0, 0.6);
}
#app>footer
{
    position: absolute;
    bottom: 0;
    font-size: 0.75em;
    padding: 0.25em;
    color: WhiteSmoke;
    background-color: #006;
}

#toolbar
{
    padding: 0.25em;
    font-size: 0.8em;
    color: WhiteSmoke;
    background-color: rgba(0, 0, 0, 0.4);
}

/*centers the input fields*/
#main
{
    min-width: 9em;
    max-width: 25em;
    margin: 1em auto;
}

#add-task label
{
    display: block;
    font-weight: bold;
}

/*have the text input filled to take up the entire width of the main section*/
#new-task-name
{
    font-size: 1em;
    display: block;
    width: 98%;
}

/*align the task-list width with the text input field*/
#task-list
{
    padding: 0;
}

/*give a bg color, rounded corners, and a shadow*/
#task-list .task
{
    position: relative;
    list-style: none;
    padding: 0.5em;
    margin: 0.25em;
    background-color: beige;
    border-radius: 4px;
    box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.6);

/*provide visual feedback to user when they select a task*/
    -webkit-transition: all 0.25s ease;
    -moz-transition: all 0.25s ease;
    -o-transition: all 0.25s ease;
    transition: all 0.25s ease;
}
#task-list .task:hover
{
    background-color: white;
}

/*increase padding to make element bigger, add a border, and change bg color*/
#task-list .task.selected
{
    padding: 0.6em 0.5em;
    border: 2px solid orange;
    border-radius: 6px;
    background-color: white;
}
#task-list .task input.task-name
{
    margin: 0;
    font-size: 1em;
}

/*add a border around the task buttons to group them, and move them over
to the upper-right side of task element*/
#task-list .task .tools
{
    position: absolute;
    top: 0.25em;
    right: 0.25em;
    border: 1px solid black;
    border-radius: 2px;
    opacity: 0;  /*hide the task action buttons until the user moves
                the mouse over a task or selects a task*/
    padding: 1px;
    -webkit-transition: all 0.25s ease;
    -moz-transition: all 0.25s ease;
    -o-transition: all 0.25s ease;
    transition: all 0.25s ease;
}

/*make the task buttons appear to fade in when the user hovers over a task*/
#task-list .task:hover .tools,
/*add a selector to make the task buttons show up when a task is selected*/
#task-list .task.selected .tools
{
    opacity: 1;
}

/*replace arrows with icons*/
#task-list .task .tools button,
#task-list .task .toggle-details
{
    margin: 0;
    padding: 0;
    width: 16px;
    height: 16px;
    background: url(images/icons.png) no-repeat;
    border: none;
    color: transparent;
}
#task-list .task .tools button.delete
{
    background-position: 0 0;
}
#task-list .task .tools button.move-up
{
    background-position: -16px 0;
}
#task-list .task .tools button.move-down
{
    background-position: -32px 0;
}
#task-list .task button.toggle-details
{
    background-position: 0 -16px;
}
#task-list .task button.toggle-details.expanded
{
    background-position: -16px -16px;
}

#task-list .task .details
{
    display: none;
    background-color: gray;
    color: white;
    border-radius: 4px;
    margin-top: 0.5em;
    padding: .25em;
    overflow: auto;
}

#task-list .task .details label
{
    width: 8em;
    text-align: right;
    display: inline-block;
    vertical-align: top;
    font-size: .8em;
}

#task-list .task .details select
{
    width: 8em;
}


appStorage.js

function AppStorage(appName)
{
    var prefix = (appName ? appName + "." : "");

    /** Determine if local storage available */
    this.localStorageSupported = (('localStorage' in window) && window['localStorage']);

    /** Sets the value with the specified key into localStorage */
    this.setValue = function(key, val)
    {
        if (this.localStorageSupported) localStorage.setItem(prefix + key, JSON.stringify(val));
        return this;
    };

    /**
     * Gets the value with the specified key from localStorage
     * @returns The value or null if not found
     */
    this.getValue = function(key)
    {
        if (this.localStorageSupported) return JSON.parse(localStorage.getItem(prefix + key));
        else return null;
    };

    /** Removes the value with the specified key */
    this.removeValue = function(key)
    {
        if (this.localStorageSupported) localStorage.removeItem(prefix + key);
        return this;
    };

    /** Removes all items associated with the app */
    this.removeAll = function()
    {
        var keys = this.getKeys();
        for (var i in keys)
        {
            this.remove(keys[i]);
        }
        return this;
    };

    /**
     * If the specified key has a value in localStorage
     * @returns True if the key has a value
     */
    this.contains = function(key)
    {
        return this.get(key) !== null;
    };

    /**
     * Gets the keys from localStorage for the application that optionally match a filter
     * returns An array of keys
     */
    this.getKeys = function(filter)
    {
        var keys = [];
        if (this.localStorageSupported)
        {
            for (var key in localStorage)
            {
                if (isAppKey(key))
                {
                    // Remove the prefix from the key
                    if (prefix) key = key.slice(prefix.length);
                    // Check the filter
                    if (!filter || filter(key))
                    {
                        keys.push(key);
                    }
                }
            }
        }

        return keys;
    };

    function isAppKey(key)
    {
        if (prefix)
        {
            return key.indexOf(prefix) === 0;
        }
        return true;
    };
}

3.运行效果

4.源码地址

https://download.csdn.net/download/zang141588761/11195555

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蚂蚁_CrkRes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值