开源桌面系统,极简单的mvc设计、数据绑定实现、微事件实现等等。
下载地址:http://git.oschina.net/eternal_rider/sapling/attach_files
设计如下图:
Controller.js
var DtController={
cache:{},
pubevt:function (topic,args,context) {
var evtcontext = context || window,
subs = evtcontext.DtController.cache[topic],
len = subs ? subs.length : 0;
while (len--) {
subs[len].apply(evtcontext, args || []);
}
},
subevt:function (topic,callback) {
if (!DtController.cache[topic]) {
DtController.cache[topic] = [];
}
DtController.cache[topic].push(callback);
return [topic, callback];
},
unsubevt:function (handle,callback) {
var subs = DtController.cache[callback ? handle : handle[0]],
callback = callback || handle[1],
len = subs ? subs.length : 0;
while (len--) {
if (subs[len] === callback) {
subs.splice(len, 1);
}
}
},
bindmodel:function(model,callback){
Object.observe(model, callback);
},
init:function(){
DtController.subevt('/dtname/set',DtModel.setDtname);
DtController.subevt('/alias/set',DtModel.setAlias);
DtController.subevt('/theme/set',DtModel.setTheme);
DtController.subevt('/wallpaper/set',DtModel.setWallpaper);
DtController.subevt('/mm/load',DtModel.loadMenu);
DtController.subevt('/mm/app/set',DtModel.setApp);
DtController.subevt('/app/xy/set',DtModel.setAppXY);
DtController.bindmodel(DtModel,function(data){
data.forEach(function(item, i){
switch(item.name){
case 'theme':
DtView.setTheme(item.object[item.name]);
break;
case 'wallpaper':
DtView.setWallpaper(item.object[item.name]);
break;
case 'alias':
DtView.setAlias(item.object[item.name]);
break;
case 'dtname':
DtView.setDtname(item.object[item.name]);
break;
case 'menus':
DtView.setMenus(item.object[item.name]);
break;
case 'apps':
DtView.setApps(item.object[item.name].list);
break;
};
//console.log(change.type, change.name, change.oldValue);
DtView.setNotifications('监听到DtModel中' + item.name+',触发'+ item.type+'事件');
});
});
DtController.pubevt('/mm/load',[]);
var urlstr=window.location.href,
username=urlstr.substr(urlstr.indexOf("?")+1);
DtModel.setUserName(username);
DtView.init();
}
};
var DtModel = {
dtname:"",
username:"",
alias:"",
theme:"",
wallpaper:{},
menus:{},
apps:{},
storage:window.localStorage,
loadMenu:function(){
//初始化开始菜单和邮件菜单
$.getJSON("assets/menu.json", function(data) {
if (data) {
var mm_tmp = [],app_tmp = [];
$(data.menu).each(function(i, item) {
mm_tmp.push(item);
});
$(data.app).each(function(i, item) {
app_tmp.push(item);
});
var obj = {mm:mm_tmp,app:app_tmp};
DtModel.menus = obj;
DtModel.load();
}
});
//初始化桌面布局菜单
},
setDtname:function(name){
DtModel.dtname = name;
DtModel.save();
},
setUserName:function(username){
DtModel.username = username;
},
setAlias:function(alias){
DtModel.alias = alias;
DtModel.save();
},
setTheme:function(theme){
DtModel.theme = theme.colors;
DtModel.save();
},
setWallpaper:function(data){
DtModel.wallpaper = data;
DtModel.save();
},
setApp:function(id){
var list = $.extend([],DtModel.apps.list || []);
$.each(list, function(i,data){
if(data.id == id){
list[i].state = list[i].state ==0?1:0;
id = "-1";
return false;
}
});
if(id != "-1"){
$.each(DtModel.menus.app, function(i,data){
if(data.id == id){
data.state = 1;
list.push(data);
return false;
}
});
}
DtModel.apps = {list:list};
DtModel.save();
},
setAppXY:function(id,x,y){
$.each(DtModel.apps.list, function(i,data){
if(data.id == id){
DtModel.apps.list[i].x=x,DtModel.apps.list[i].y=y;
return false;
}
});
DtModel.apps = {list:DtModel.apps.list};
DtModel.save();
},
save:function(){
if(DtModel.storage) {
var data = {};
data.dtname = DtModel.dtname;
data.username = DtModel.username;
data.alias = DtModel.alias;
data.theme=DtModel.theme;
data.wallpaper = DtModel.wallpaper;
data.apps=DtModel.apps;
DtModel.storage.sapling = JSON.stringify(data);
//通过websocket保存到服务器
}else{
alert('不支持LocalStorage');
}
},
load:function(){
if(DtModel.storage) {
if(DtModel.storage.sapling){
var data = JSON.parse(DtModel.storage.sapling);
DtModel.dtname = data.dtname;
DtModel.username = data.username;
DtModel.alias = data.alias ? data.alias:data.username;
DtModel.theme = data.theme;
DtModel.wallpaper = data.wallpaper;
DtModel.apps = data.apps;
}else{
DtModel.alias = DtModel.username;
}
}else{
alert('不支持LocalStorage');
}
}
}
var DtView = {
"init":function(){
setInterval(function() {
var time = new Date();
$("#time").html(time.toLocaleTimeString());
}, 1000);
using('calendar',function(){
$('#calendar').calendar({
firstDay:1,
width:250,
height:250
});
});
using('textbox',function(){
$('#dt_name').textbox({
onClickButton:function(){
var text = $('#dt_name').textbox('getText');
if(text){
DtController.pubevt('/dtname/set',[text]);
}
}
});
$('#alias').textbox({
onClickButton:function(){
var text = $('#alias').textbox('getText');
if(text){
DtController.pubevt('/alias/set',[text]);
}
}
});
});
$("#start").mouseenter(function(e) {
e.preventDefault();
$(this).attr("src", "assets/ima/2.jpg");
using("menu", function() {
$('#startmm').menu('show', {
left : 0,
top : 40
});
});
}).mouseleave(function() {
$(this).attr("src", "assets/ima/1.jpg");
});
$('#dock').on('click','li',function(ev){
var target = $(this).find('a').attr('href');
if($(target).dialog('options').minimized){
$(target).dialog('open');
}else{
$(target).dialog('minimize');
}
ev.preventDefault();
ev.stopPropagation();
});
$('#user').mouseenter(function(ev){
ev.preventDefault();
ev.stopPropagation();
$('#calendar').hide();
$('#user_panel').fadeIn();
});
$('#user_panel').mouseleave(function() {
$('#user_panel').fadeOut();
});
$('#time').mouseenter(function(ev){
ev.preventDefault();
ev.stopPropagation();
$('#user_panel').hide();
$('#calendar').fadeIn();
});
$('#calendar').mouseleave(function() {
$('#calendar').fadeOut();
});
$('#desktop,#task_bar').on('contextmenu',function(e){
e.preventDefault();
var target=e.target||e.srcElement;
var tid = $(target).attr('id');
if(tid == 'desktop'){
using("menu", function() {
$('#mm-setup').menu('show', {
left: e.pageX,
top: e.pageY
});
});
}else if(tid == 'task_bar'){
alert('任务栏的右键事件');
}else{
return false;
}
});
$('#setup_app').on('click','li',function(ev){
DtController.pubevt('/mm/app/set',[$(this).attr('id')]);
ev.preventDefault();
ev.stopPropagation();
});
$('#user_blog').on('click',function(ev){
ev.preventDefault();
ev.stopPropagation();
DtView.dialogHandler({
"id":"myblog",
"title":"作者博客",
"link":"http://my.oschina.net/eternal/blog",
"load":"iframe",
"icon":"world",
"width":1280,
"height":685
});
});
$('#user_about').on('click',function(ev){
ev.preventDefault();
ev.stopPropagation();
DtView.dialogHandler({
"id":"aboutme",
"title":"关于作者",
"link":"apps/about/index.html",
"load":"iframe",
"icon":"user",
"maximized":true
});
});
$('#help_user').on('click',function(ev){
ev.preventDefault();
ev.stopPropagation();
DtView.dialogHandler({
"id":"helpme",
"title":"随便给点吧",
"link":"apps/helpme/index.html",
"load":"iframe",
"icon":"heart",
"maximized":true
});
});
$('#wallpapers_mm').on('click',function(ev){
ev.preventDefault();
ev.stopPropagation();
DtView.dialogHandler({
"id":"wallpapers",
"title":"桌面壁纸",
"link":"apps/wallpaper/index.html",
"load":"iframe",
"icon":"customization",
"width":1280,
"height":685
});
});
$('#logout').on('click',function(ev){
ev.preventDefault();
ev.stopPropagation();
if (confirm("确认退出系统吗?")==true){
window.location.href="index.html";
}
});
},
setDtname:function(name){
document.title = name;
using('textbox',function(){
$('#dt_name').textbox('setText',name);
});
},
setAlias:function(name){
$('#user').text(name);
using('textbox',function(){
$('#alias').textbox('setText',name);
});
},
setApps:function(list){
if(!list){
return false;
}
$.each(list, function(i,data){
var hasapp = $("#desktop").children("#dt_"+data.id).html();
if(!hasapp){
var app = {id:data.id,width:data.width,height:data.height,title:data.title,x:data.x,y:data.y};
$("#dtapp_tmpl").tmpl(app).appendTo("#desktop");
var $appi = $("<iframe border=0 frameborder=0 style='width:100%;height:100%;' scrolling='yes' src='"+data.link+"'></iframe>");
$("#dt_body_"+data.id).html($appi);
using("draggable",function(){
$("#dt_"+data.id).draggable({onStopDrag:function(e){
var x = $(this).offset().left,y = $(this).offset().top-41;
DtController.pubevt('/app/xy/set',[data.id,x,y]);
}});
});
}else{
if(data.state == 0){
$("#desktop").children("#dt_"+data.id).remove();
}
}
});
},
setMenus:function(menus){
$("#startmm_tmpl").tmpl(menus.mm).appendTo("#startmm");
using('menu',function(){
$('#startmm').menu({
onClick:function(item){
DtView.menuHandler(item);
}
});
});
$("#app_tmpl").tmpl(menus.app).appendTo("#setup_app");
},
setTheme:function(theme){
var colors = theme.split(',');
$('#task_bar').css('background-color',colors[0]).css('border-bottom','1px solid '+colors[1]);
$('body').css('background-color',colors[2]);
},
setWallpaper:function(data){
if(data.type == 'rgb'){
$('body').css('background',data.name);
}else{
$('body').css('background','#777777 url(assets/ima/'+data.name+')');
}
},
setNotifications:function(content){
var $lists = $("#user_panel_news").children(".notifications");
if($lists.length >= 3){
$lists[2].remove();
}
$("#notifications_tmpl").tmpl({content:content}).prependTo("#user_panel_news");
},
menuHandler:function(item) {
var menumodel = {};
$.each(DtModel.menus.mm, function(i,data){
if(data.id == item.id){
menumodel = data;
return false;
}
});
if(menumodel.id){
DtView.dialogHandler(menumodel);
}
},
dialogHandler:function(menumodel) {
if ($("#mm_"+menumodel.id).length > 0) {
$("#mm_"+menumodel.id).html("");
} else {
$("#desktop").append("<div id='mm_"+menumodel.id+"' style='overflow: hidden;'></div>");
}
using('dialog', function() {
var dlgconfig = {
title:' '+menumodel.title,
width:menumodel.width,
height:menumodel.height,
iconCls:'icon-'+menumodel.icon,
collapsible:menumodel.collapsible||true,
minimizable:menumodel.minimizable||true,
maximizable:menumodel.maximizable||true,
resizable:menumodel.resizable||true,
draggable:menumodel.draggable||true,
inline:true,
shadow:true,
maximized:menumodel.maximized||false,
onBeforeClose:function(){
$('#dock_'+menumodel.id).remove();
$(this).parent().next().remove();
$(this).parent().remove();
},
content : "<iframe border=0 frameborder=0 style='width:100%;height:100%;' scrolling='yes' src='"+menumodel.link+"' sandbox=\"allow-scripts allow-same-origin allow-forms\"></iframe>"
};
menumodel.load == "ajax"?dlgconfig.href=menumodel.link:"";
$("#mm_"+menumodel.id).dialog(dlgconfig);
});
$('<li id="dock_'+menumodel.id+'"><a href="#mm_'+menumodel.id+'"><img src="assets/ima/' + menumodel.icon + '_22.png" />'+menumodel.title+'</a></li>').appendTo('#dock');
}
};