OSDN Git Service

Merge pull request #103 from mtsgi/feature/kit-disabled-kaf
[kit/kit.git] / system.js
index 6bea767..b8f6871 100644 (file)
--- a/system.js
+++ b/system.js
@@ -504,93 +504,130 @@ async function launch( str, args, dir ) {
         try{
             $.getJSON( S.launchpath[_pid] + '/define.json', appData ).fail( () => {
                 Notification.push('kitアプリをロードできません。', `${str}を展開できませんでした。`, 'system');
+                System.launchLock = false;
+                pid++;
             } );
         }
         catch(error){
             Notification.push( "System Error", error, "system" );
+            System.launchLock = false;
         }
     }
 }
 
 async function appData(data) {
-    if(data.support && data.support.multiple == false){
-        if( Object.values(process).map(p => p.id).includes(data.id) ){
-            Notification.push('多重起動エラー', `アプリケーション「${data.name}」の多重起動は許可されていません。`, 'system');
+    let _support = {
+        fullscreen: false,
+        resize: false,
+        darkmode: false,
+        kaf: true,
+        multiple: true
+    }, _size = {}, _resize = false;
+    if (data.support) _support = {
+        fullscreen: typeof data.support.fullscreen == "undefined" ? false : data.support.fullscreen,
+        resize: typeof data.support.resize == "undefined" ? false : data.support.resize,
+        darkmode: typeof data.support.darkmode == "undefined" ? false : data.support.darkmode,
+        kaf: typeof data.support.kaf == "undefined" ? true : data.support.kaf,
+        multiple: typeof data.support.multiple == "undefined" ? true : data.support.multiple
+    }
+    if (data.size) _size = {
+        width: data.size.width || 'auto',
+        height: data.size.height || 'auto'
+    };
+    if (data.resize) _resize = data.resize;
+    const defobj = {
+        id: data.id || null,
+        name: data.name || 'アプリ名なし',
+        icon: data.icon || 'none',
+        version: data.version || null,
+        author: data.author || null,
+        support: _support,
+        size: _size,
+        resize: _resize,
+        view: data.view || 'default.html',
+        script: data.script || 'none',
+        css: data.css || 'none'
+    }
+    if (!data.id || !data.version || !data.author) {
+        Notification.push('起動エラー', '起動に失敗しました。詳細情報を得るためには、デバッグモードを有効化してください。', 'system');
+        Notification.push('debug', '起動エラー:id, version, authorは必須定義項目です。', 'system');
+        System.launchLock = false;
+        return;
+    }
+    if (defobj.support.multiple == false) {
+        if (Object.values(process).map(p => p.id).includes(defobj.id)) {
+            Notification.push('多重起動エラー', `アプリケーション「${defobj.name}」の多重起動は許可されていません。`, 'system');
             System.launchLock = false;
             return;
         }
     }
     let _pid = pid;
-    process[String( _pid )] = {
-        id: data.id,
+    process[String(_pid)] = {
+        id: defobj.id,
         time: System.time.obj.toLocaleString(),
         isactive: false,
         preventclose: false,
-        title: data.name
+        title: defobj.name
     };
     System.appCache[System.launchpath[pid]] = data;
     app = new App(_pid);
     let _taskAppend = `<span id='t${_pid}'>`;
-    if( data.icon && data.icon != "none" ) _taskAppend += `<img src='${S.launchpath[_pid]}/${data.icon}'>`;
-    _taskAppend += `<span id='tname${_pid}'>${data.name}<span></span>`;
-    $( "#tasks" ).append( _taskAppend );
-    $( "#t" + _pid ).addClass( "task" ).on({
+    const _iconPath = app.getPath(defobj.icon).toString();
+    const _viewPath = app.getPath(defobj.view).toString();
+    if(defobj.icon != 'none') _taskAppend += `<img src='${_iconPath}'>`;
+    _taskAppend += `<span id='tname${_pid}'>${defobj.name}<span></span>`;
+    $("#tasks").append(_taskAppend);
+    $("#t" + _pid).addClass("task").on({
         click: function() {
-            if( process[_pid].isactive || $(this).hasClass("task-min") ) KWS.min( _pid );
-            else{
+            if ( process[_pid].isactive || $(this).hasClass("task-min") ) KWS.min(_pid);
+            else {
                 $("#w"+_pid).css("z-index", KWS.windowIndex + 1);
                 KWS.refreshWindowIndex();
             }
         },
         mouseenter: function() {
-            $("#task-ctx-name").text(data.name || 'アプリ名なし');
-            if( data.icon && data.icon != "none" ) $("#task-ctx-img").attr( "src", System.launchpath[_pid] + "/" + data.icon );
-            else $( "#task-ctx-img" ).hide();
-            $("#task-ctx-ver").text(data.version + "/pid:" + _pid);
-            $("#task-ctx-info").off().on("click", function() { System.appInfo( _pid )});
-            $("#task-ctx-sshot").off().on("click", function() { S.screenshot(_pid, true) });
-            $("#task-ctx-min").off().on("click", function() { KWS.min( String(_pid) ) });
-            if( $(this).hasClass("t-active") ) $( "#task-ctx-front" ).hide();
-            else $( "#task-ctx-front" ).show();
+            $("#task-ctx-name").text(defobj.name);
+            if(defobj.icon != "none") $("#task-ctx-img").show().attr("src", _iconPath);
+            else $("#task-ctx-img").hide();
+            $("#task-ctx-ver").text(`v${defobj.version} pid${_pid}`);
+            $("#task-ctx-info").off().on("click", function() { System.appInfo(_pid)});
+            $("#task-ctx-sshot").off().on("click", function() { System.screenshot(_pid, true) });
+            $("#task-ctx-min").off().on("click", function() { KWS.min(String(_pid)) });
+            if($(this).hasClass('t-active')) $('#task-ctx-front').hide();
+            else $('#task-ctx-front').show();
             $("#task-ctx-front").off().on('click', function() {
-                $("#w"+_pid).css("z-index", KWS.windowIndex + 1);
+                $("#w"+_pid).css("z-index", KWS.windowIndex+1);
                 KWS.refreshWindowIndex();
             });
             $("#task-ctx-close").off().on("click", () => System.close(_pid));
-            $("#task-ctx-kill").off().on("click", () => System.kill( data.id));
+            $("#task-ctx-kill").off().on("click", () => System.kill(defobj.id));
             const _ctxleft = $(this).offset().left, _ctxtop = window.innerHeight - $(this).offset().top;
             if( _ctxleft != $("#task-ctx").offset().left ) $("#task-ctx").hide();
             $("#task-ctx").css("left", _ctxleft).css("bottom", _ctxtop).show();
         }
     } );
-    $( "section, #kit-tasks" ).on( "mouseenter", function() {
-        $( "#task-ctx" ).fadeOut( 200 );
-    } );
-    $( "#t" + _pid ).on({
+    $("section, #kit-tasks").on('mouseenter', function() { $('#task-ctx').fadeOut(200) });
+    $("#t" + _pid).on({
         mouseenter: () => {
-            prevWindowIndex = $( "#w" + _pid ).css( "z-index" );
-            $( "#w" + _pid ).addClass( "win-highlight" );
+            prevWindowIndex = $("#w" + _pid).css('z-index');
+            $("#w" + _pid).addClass('win-highlight');
         },
-        mouseleave: () => $( "#w" + _pid ).removeClass( "win-highlight" )
+        mouseleave: () => $("#w" + _pid).removeClass('win-highlight')
     });
-
     let _windowAppend = "<div id='w" + _pid + "'><div id='wt" + _pid + "' class='wt'><i class='wmzx'><span id='wm" + _pid + "'></span>";
-    if( data.support && data.support['fullscreen'] == true ) _windowAppend += "<span id='wz" + _pid + "'></span>";
+    if( defobj.support.fullscreen == true ) _windowAppend += "<span id='wz" + _pid + "'></span>";
     _windowAppend += "<span id='wx" + _pid + "'></span></i>";
-    if( data.icon && data.icon != "none" ) _windowAppend += "<img src='" + S.launchpath[_pid] + "/" + data.icon + "'>";
-    _windowAppend += "<span id='wtname" + _pid + "'>" + data.name + "</span></div><div class='winc winc-" + data.id + "' id='winc" + _pid + "'></div></div>";
-    $( "#desktop-" + currentDesktop ).append( _windowAppend );
+    if( defobj.icon != "none" ) _windowAppend += "<img src='" + _iconPath + "'>";
+    _windowAppend += "<span id='wtname" + _pid + "'>" + defobj.name + "</span></div><div class='winc winc-" + defobj.id + "' id='winc" + _pid + "'></div></div>";
+    $("#desktop-" + currentDesktop).append(_windowAppend);
 
-    if( data.support && data.support['darkmode'] == true ) $("#winc"+_pid).addClass("winc-darkmode");
+    if( defobj.support.darkmode == true ) $("#winc"+_pid).addClass('winc-darkmode');
     if( KWS.darkmode ) $("#winc"+_pid).addClass("kit-darkmode");
-
-    if( data.size ){
-        $("#winc"+_pid).css("width", data.size.width).css("height", data.size.height);
-    }
-    if( data.resize ){
-        let _minwidth = 200, _minheight = 40;
-        if( data.resize.minWidth ) _minwidth = data.resize.minWidth;
-        if( data.resize.minHeight ) _minheight = data.resize.minHeight;
+    
+    $("#winc"+_pid).css("width", defobj.size.width).css("height", defobj.size.height);
+    if( defobj.resize ){
+        let _minwidth = defobj.resize.minWidth ? defobj.resize.minWidth : 200;
+        let _minheight = defobj.resize.minHeight ? defobj.resize.minHeight : 40;
         $("#winc"+_pid).windowResizable({
             minWidth: _minwidth,
             minHeight: _minheight
@@ -620,35 +657,35 @@ async function appData(data) {
         KWS.refreshWindowIndex();
     } ).css( "left", windowPos + "px" ).css( "top", windowPos + "px" ).css( "z-index",  KWS.windowIndex );
     KWS.refreshWindowIndex();
-    if( data.support && data.support['fullscreen'] == true ) $( `#wt${_pid}` ).on("dblclick", () => KWS.max( _pid ));
+    if(defobj.support.fullscreen == true) $(`#wt${_pid}`).on("dblclick", () => KWS.max(_pid));
     $( `#wm${_pid}` ).addClass("wm fa fa-window-minimize").on("click", () => KWS.min( _pid ));
     $( `#wz${_pid}` ).addClass("wz fas fa-square").on("click", () => KWS.max( _pid ));
     $( `#wx${_pid}` ).addClass("wx fa fa-times").on("click", () => System.close( _pid ));
-    $( "#winc" + _pid ).resizable( {
-        minWidth: "200"
-    } ).load( System.launchpath[_pid] + "/" + data.view, (r, s, x) => {
-        if( s == "error" ){
-            Notification.push("起動に失敗:" + x.status, x.statusText);
+    $( "#winc" + _pid ).resizable().load(app.getPath(defobj.view), (r, s, x) => {
+        if(s == "error"){
+            Notification.push("起動に失敗しました " + x.status, 'テンプレートにアクセスできません。' + x.statusText, 'system');
+            System.launchLock = false;
+            pid++;
             return false;
         }
-        if( !data.script || data.script != "none" ) $.getScript( System.launchpath[_pid] + "/" + data.script, () => {
-            if( !data.support || data.support['kaf'] != false ) App.kaf(_pid);
-            pid++;
-        }).fail( () => {
-            App.kaf(_pid);
+        if( defobj.css != "none" && !document.querySelector(`#kit-style-${defobj.id}`) ){
+            $("head").append('<link href="' + app.getPath(defobj.css) + '" rel="stylesheet" id="kit-style-' + data.id + '"></link>');
+        }
+        if(defobj.script != "none") $.getScript(app.getPath(defobj.script), () => {
+            if( defobj.support.kaf == true ) App.kaf(_pid);
             pid++;
+        }).fail(() => {
+            if( defobj.support.kaf == true ) App.kaf(_pid)
+            pid ++;
         });
-        else if( !data.support || data.support['kaf'] != false ){
+        else if( defobj.support.kaf == true ){
             App.kaf(_pid);
             pid++;
         }
         else pid++;
-        if( data.css != "none" && $("#kit-style-"+data.id).length == 0 ){
-            $( "head" ).append( '<link href="' + System.launchpath[_pid] + '/' + data.css + '" rel="stylesheet" id="kit-style-' + data.id + '"></link>' );
-        }
         localStorage.setItem( "kit-pid", pid );
         System.launchLock = false;
-    } );
+    });
 }
 
 const System = new function() {
@@ -704,20 +741,15 @@ const System = new function() {
     this.noop = () => {}
 
     this.launchLock = false;
-    
-    this.waitLaunchUnlock = (callback) => {
-        setTimeout(()=>{
-            if(this.ajaxLock){
-                this.waitLaunchUnlock(callback);
-            }else{
-                return callback();
-            }
-        }, 100)
-    }
 
     this.ajaxWait = () =>{
         return new Promise(resolve =>{
-             System.waitLaunchUnlock(resolve);
+            let interval = setInterval(()=>{
+                if(this.launchLock === false) {
+                    clearInterval(interval);
+                    resolve();
+                }
+            }, 100)
         });
     }
 
@@ -1015,10 +1047,12 @@ const System = new function() {
             try{
                 $.getJSON( _path + '/define.json', appData ).fail( () => {
                     Notification.push('kitアプリをロードできません。', `${_path}を展開できませんでした。`, 'system');
+                    System.launchLock = false;
                 } );
             }
             catch(error){
                 Notification.push( "System Error", error, "system" );
+                System.launchLock = false;
             }
         }
     }
@@ -1408,12 +1442,28 @@ class App {
         if( _value !== undefined ) {
             S.dom(_pid, `[kit\\:bind=${_name}]`).val( _value );
             S.dom(_pid, `[kit\\:observe=${_name}]`).text( _value );
-            if( _value ) S.dom(_pid, `[kit\\:if=${_name}]`).show();
-            else S.dom(_pid, `[kit\\:if=${_name}]`).hide();
+            S.dom(_pid, `template[kit\\:for=${_name}] + kit-for`).text('');
+            if (typeof _value == 'object'){
+                for(let elem of S.qs(_pid, `template[kit\\:for=${_name}] + kit-for`)){
+                    let _rep = App.d[_pid][`__kaf_node_id_${elem.getAttribute('kaf-node-id')}`], _result = '';
+                    for(let i in _value) {
+                        _result += _rep.replace(/{{\s*key\s*}}/g, i).replace(/{{\s*value\s*}}/g, _value[i]);
+                    }
+                    elem.innerHTML = _result;
+                }
+            }
+            if( _value ) {
+                S.dom(_pid, `[kit\\:if=${_name}]`).show();
+                S.dom(_pid, `[kit\\:disabled=${_name}]`).prop('disabled', true);
+            }
+            else{
+                S.dom(_pid, `[kit\\:if=${_name}]`).hide();
+                S.dom(_pid, `[kit\\:disabled=${_name}]`).prop('disabled', false).removeClass('-disabled');
+            }
             return App.d[_pid][_name] = _value;
         }
         else if( _name ) return App.d[_pid][_name];
-        else return App.d[_pid];
+        else return Object.fromEntries( Object.entries(App.d[_pid] || {}).filter(d => d[0].indexOf("__") != 0) );
     }
 
     static event( _pid, _name, _event ) {
@@ -1444,11 +1494,13 @@ class App {
             "[kit-value]",
             "[kit-color]",
             "[kit\\:if]",
-            "[kit-if]"
+            "[kit-if]",
+            "[kit\\:for]"
         ]
         const PID = _pid;
         const DATA = App.data(_pid);
         const ARGS = System.args[_pid];
+        let _kaf_node_id = 0;
         for( let i of S.qs(_pid, ...attrs) ){
             if( i.hasAttribute("kit-ref") ){
                 $(i).on("click", () => App.load(_pid, i.getAttribute("kit-ref")) );
@@ -1457,7 +1509,9 @@ class App {
                 let _eqs = i.getAttribute("kit-e").split(",");
                 for( let k of _eqs ){
                     let _eq = k.split(" ");
-                    $(i).on( _eq[1]||"click", App.e[_pid][_eq[0]] );
+                    $(i).on( _eq[1]||'click', (e) => {
+                        if(e.target.classList.contains('-disabled') === false) App.e[_pid][_eq[0]]();
+                    } );
                 }
             }
             if( i.hasAttribute("kit-src") ){
@@ -1484,8 +1538,14 @@ class App {
                     let _name = i.getAttribute("kit:bind");
                     App.d[_pid][_name] = i.value;
                     S.dom(_pid, `[kit\\:observe=${_name}]`).text( i.value );
-                    if( i.value ) S.dom(_pid, `[kit\\:if=${_name}]`).show();
-                    else S.dom(_pid, `[kit\\:if=${_name}]`).hide();
+                    if( i.value ){
+                        S.dom(_pid, `[kit\\:if=${_name}]`).show();
+                        S.dom(_pid, `[kit\\:disabled=${_name}]`).prop('disabled', true).addClass('-disabled');
+                    }
+                    else{
+                        S.dom(_pid, `[kit\\:if=${_name}]`).hide();
+                        S.dom(_pid, `[kit\\:disabled=${_name}]`).prop('disabled', false).removeClass('-disabled');
+                    }
                 } );
             }
             if( i.hasAttribute("kit:observe") ){
@@ -1506,12 +1566,28 @@ class App {
                 }
                 else $(i).hide();
             }
+            if( i.hasAttribute("kit:disabled") ){
+                if( App.d[_pid][i.getAttribute("kit:if")] ){
+                    i.disabled = true;
+                    i.classList.add('-disabled');
+                }
+                else i.disabled = false;
+            }
             if( i.hasAttribute("kit-if") ){
                 if( eval( i.getAttribute("kit-if")) ){
                     $(i).show();
                 }
                 else $(i).hide();
             }
+            if( i.hasAttribute("kit:for") ){
+                if ('content' in document.createElement('template')) {
+                    i.setAttribute('kaf-node-id', _kaf_node_id);
+                    App.d[_pid][`__kaf_node_id_${_kaf_node_id}`] = i.innerHTML;
+                    i.insertAdjacentHTML('afterend', `<kit-for kaf-node-id="${_kaf_node_id}"></kit-for>`);
+                }
+                else i.style.display = 'none';
+            }
+            _kaf_node_id ++;
         }
     }