From cfe67be31758b6df9833f4baab2fb3d79ea4f10f Mon Sep 17 00:00:00 2001 From: Sheng Zhao Date: Wed, 1 Jul 2015 22:07:42 +1000 Subject: [PATCH 01/21] added: support clientHeight,clientWith, scrollTop, scrollLeft fixed: exception happens when binding to the "text" access point of a element fixed: source tab can't get all of the example htmls --- example/js/sourceTab.js | 2 +- src/core/AddonHTMLAPProvider.js | 3 ++- src/core/HTMLAPProvider.js | 21 +++++++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/example/js/sourceTab.js b/example/js/sourceTab.js index af52944..dcd5108 100644 --- a/example/js/sourceTab.js +++ b/example/js/sourceTab.js @@ -8,7 +8,7 @@ window.sourceTab = { $(document).ready(function () { if($(".knot_example").length > 0) { var text = ""; - for(var i=0; i<$("body>.knot_example").length; i++) { + for(var i=0; i<$("body .knot_example").length; i++) { if(text) { text += "\r\n\r\n\r\n\r\n"; } diff --git a/src/core/AddonHTMLAPProvider.js b/src/core/AddonHTMLAPProvider.js index 6d9c7a9..b15d32d 100644 --- a/src/core/AddonHTMLAPProvider.js +++ b/src/core/AddonHTMLAPProvider.js @@ -260,10 +260,11 @@ }, doesSupportMonitoring: function (target, apName) { if(apName[0] === "#") { + target = document.querySelector(__private.HTMLAPHelper.getSelectorFromAPDescription(apName)); apName = __private.HTMLAPHelper.getPropertyNameFromAPDescription(apName); } - return target.tagName.toLowerCase() ==="select" && (apName === "selectedData" || apName === "value"); + return target && target.tagName.toLowerCase() ==="select" && (apName === "selectedData" || apName === "value"); }, monitor: function (target, apName, callback) { if(apName[0] === "#") { diff --git a/src/core/HTMLAPProvider.js b/src/core/HTMLAPProvider.js index c3883e4..34c6f66 100644 --- a/src/core/HTMLAPProvider.js +++ b/src/core/HTMLAPProvider.js @@ -14,8 +14,17 @@ htmlEventInfo["input.value"] = "change"; htmlEventInfo["textarea.value"] = "change"; htmlEventInfo["input.checked"] = "change"; - htmlEventInfo["select.selectedindex"] = "change"; + htmlEventInfo["select.selectedIndex"] = "change"; htmlEventInfo["select.value"] = "change"; + htmlEventInfo["*.clientWith"] = "resize"; + htmlEventInfo["*.clientHeight"] = "resize"; + htmlEventInfo["*.scrollTop"] = "scroll"; + htmlEventInfo["*.scrollLeft"] = "scroll"; + + function getEvent(target, apName){ + var eventKey = target.tagName.toLowerCase() + "." +apName; + return (htmlEventInfo[eventKey] || htmlEventInfo["*." + apName]); + } //provide some helper functions for the HTML elements __private.HTMLAPHelper = { @@ -297,8 +306,8 @@ if(!target) { return false; } - var eventKey = target.tagName.toLowerCase() + "." +apName.toLowerCase(); - return (htmlEventInfo[eventKey]); + var eventKey = target.tagName.toLowerCase() + "." +apName; + return (htmlEventInfo[eventKey] || htmlEventInfo["*." + apName]); }, monitor: function (target, apName, callback, options) { @@ -307,7 +316,7 @@ apName = __private.HTMLAPHelper.getPropertyNameFromAPDescription(apName); } - var eventKey = target.tagName.toLowerCase() + "." +apName.toLowerCase(); + var eventKey = target.tagName.toLowerCase() + "." +apName; var events = htmlEventInfo[eventKey].split(","); for(var i=0; i Date: Fri, 3 Jul 2015 00:42:35 +1000 Subject: [PATCH 02/21] added: value set direction support added: global object binding added: windows .hash status fixed: doesn't work on webpage with SVG --- example/bookstore.html | 74 ++++++++++++++++++++++ example/cbs/bookstore.cbs | 57 +++++++++++++++++ example/js/bookstore.js | 44 +++++++++++++ example/js/sourceTab.js | 8 ++- example/rsc/bookstore.json | 92 +++++++++++++++++++++++++++ example/styles/bookstore.css | 64 +++++++++++++++++++ src/core/HTMLKnotBuilder.js | 75 +++++++++++++++++++--- src/core/KnotManager.js | 44 ++++++++++--- src/core/OptionParser.js | 31 ++++++++- src/core/PrivateScope.js | 3 + src/core/Utility.js | 15 ++++- src/core/WindowHashStatus.js | 114 ++++++++++++++++++++++++++++++++++ src/debugger/debugger.cbs | 40 ++++++------ src/debugger/debugger.js | 6 +- test/HTMLKnotBuilder.test.js | 62 +++++++++++++++++- test/KnotManager.test.js | 51 ++++++++++++++- test/OptionParser.test.js | 22 ++++++- test/PrivateScopeTest.html | 5 +- test/Utility.test.js | 7 +++ test/WindowHashStatus.test.js | 78 +++++++++++++++++++++++ 20 files changed, 841 insertions(+), 51 deletions(-) create mode 100644 example/bookstore.html create mode 100644 example/cbs/bookstore.cbs create mode 100644 example/js/bookstore.js create mode 100644 example/rsc/bookstore.json create mode 100644 example/styles/bookstore.css create mode 100644 src/core/WindowHashStatus.js create mode 100644 test/WindowHashStatus.test.js diff --git a/example/bookstore.html b/example/bookstore.html new file mode 100644 index 0000000..b048603 --- /dev/null +++ b/example/bookstore.html @@ -0,0 +1,74 @@ + + + + Knot.js Example - Todo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Knot.js example - Bookstore

+ All of the text and images are from Amazon.com + + + +
+ +
    +
  • + +
    +
  • +
+ +
+

+ +

+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/example/cbs/bookstore.cbs b/example/cbs/bookstore.cbs new file mode 100644 index 0000000..20b08cd --- /dev/null +++ b/example/cbs/bookstore.cbs @@ -0,0 +1,57 @@ + +/bookStoreModel{ + selectedCategory: (window.hash.category & /bookStoreModel.categories) > { return } +} + + +body{ + dataContext: /bookStoreModel; +} +#navMenu>ul{ + foreach: categories; + + => >li{ + text: name; + @click: @{window.bookStoreModel.selectedCategory = this;}; + class: (/bookStoreModel.selectedCategory && *LEFT)>{return value[0]===value[1]?"+selected":"-selected";} + } +} + +#booksList{ + foreach: items; + + => >li{ + @click:@{window.bookStoreModel.selectedBook = this;}; + + => img{ + src: cover + }; + => div{ + text: name + }; + } +} + +#bookDetails{ + => h2{ + text: name + }; + + => img{ + src: cover + }; + + => p{ + innerHTML: intro + }; + + => button{ + @click: @{window.bookStoreModel.selectedBook = null;} + } +} + + +#contentContainer{ + content[template: @/window.bookStoreModel.contentTemplateSelector]: + (selectedCategory & selectedBook)> { return value;} +} diff --git a/example/js/bookstore.js b/example/js/bookstore.js new file mode 100644 index 0000000..1526cba --- /dev/null +++ b/example/js/bookstore.js @@ -0,0 +1,44 @@ +window.bookStoreModel = { + categories:null, + selectedCategory: null, + selectedBook: null, + + contentTemplateSelector:function(values){ + if(values[1]){ + var template = Knot.Advanced.createFromTemplate("bookDetailsTemplate", values[1], values[1]); + Knot.Advanced.setDataContext(template, values[1]); + return template; + } + else{ + if(values[0]){ + var template = Knot.Advanced.createFromTemplate("bookListTemplate", values[0], values[0]); + Knot.Advanced.setDataContext(template, values[0]); + return template; + } + } + } +}; + +Knot.ready(function(){ + $.ajax({ + type:"GET", + url:"rsc/bookstore.json" + }).then(function(ret){ + var categories = ret; + if(categories[categories.length-1].id==="all"){ + var all =[]; + for(var i=0; i 0 && !window.bookStoreModel.selectedCategory){ + window.bookStoreModel.selectedCategory = categories[0]; + } + }, + function(err){ + alert(err); + } + ); +}); \ No newline at end of file diff --git a/example/js/sourceTab.js b/example/js/sourceTab.js index dcd5108..4f51129 100644 --- a/example/js/sourceTab.js +++ b/example/js/sourceTab.js @@ -30,9 +30,11 @@ $(document).ready(function () { for(var i=0; i<$(tagSelector).length; i++) { (function () { var script = $(tagSelector).eq(i)[0]; - var data ={name:typeName, content: script.innerText, title:typeName}; + var data ={name:typeName, content: script.outerHTML, title:typeName}; + var hasTitle = false; if(script.getAttribute("title")) { data.title = script.getAttribute("title"); + hasTitle = true; } window.sourceTab.sourceInformation.push(data); if(script.src || script.href) { @@ -41,6 +43,10 @@ $(document).ready(function () { if(hr.readyState === 4) { if(hr.status === 200) { data.content = hr.responseText; + if(!hasTitle){ + var arr = (script.src || script.href).split("/"); + data.title = arr[arr.length-1]; + } } } }; diff --git a/example/rsc/bookstore.json b/example/rsc/bookstore.json new file mode 100644 index 0000000..8a30ca1 --- /dev/null +++ b/example/rsc/bookstore.json @@ -0,0 +1,92 @@ +[ + { + "id":"new", + "name":"Newly listed", + "items":[ + { + "id":1, + "name":"The Three-Body Problem", + "cover":"http://ecx.images-amazon.com/images/I/51fGDeB1DWL.jpg", + "intro":"The Three-Body Problem is the first chance for English-speaking readers to experience this multiple award winning phenomenon from China's most beloved science fiction author, Liu Cixin.Set against the backdrop of China's Cultural Revolution, a secret military project sends signals into space to establish contact with aliens. An alien civilization on the brink of destruction captures the signal and plans to invade Earth. Meanwhile, on Earth, different camps start forming, planning to either welcome the superior beings and help them take over a world seen as corrupt, or to fight against the invasion. The result is a science fiction masterpiece of enormous scope and vision." + }, + + { + "id":2, + "name":"The Dark Forest ", + "cover":"http://ecx.images-amazon.com/images/I/91HSIJIkHkL.jpg", + "intro":"This near-future trilogy is the first chance for English-speaking readers to experience this multiple-award-winning phenomenon from Cixin Liu, China's most beloved science fiction author. In Dark Forest, Earth is reeling from the revelation of a coming alien invasion-in just four centuries' time. The aliens' human collaborators may have been defeated, but the presence of the sophons, the subatomic particles that allow Trisolaris instant access to all human information, means that Earth's defense plans are totally exposed to the enemy. Only the human mind remains a secret. This is the motivation for the Wallfacer Project, a daring plan that grants four men enormous resources to design secret strategies, hidden through deceit and misdirection from Earth and Trisolaris alike. Three of the Wallfacers are influential statesmen and scientists, but the fourth is a total unknown. Luo Ji, an unambitious Chinese astronomer and sociologist, is baffled by his new status. All he knows is that he's the one Wallfacer that Trisolaris wants dead." + }, + + { + "id":3, + "name":"Fifty Shades Trilogy", + "cover":"http://ecx.images-amazon.com/images/I/71R1iAO1ltL.jpg", + "intro":"FIFTY SHADES OF GREY IS NOW A MAJOR MOTION PICTURE
Now available as a three-volume paperback boxed set, E L James’s New York Times #1 bestselling trilogy has been hailed by Entertainment Weekly as being “in a class by itself.” Beginning with the GoodReads Choice Award Romance Finalist Fifty Shades of Grey, the Fifty Shades Trilogy will obsess you, possess you, and stay with you forever.
This boxed set includes the following novels
" + }, + + { + "id":4, + "name":"Go Set a Watchman: A Novel ", + "cover":"http://ecx.images-amazon.com/images/I/A1rBZedGc0L.jpg", + "intro":"Originally written in the mid-1950s, Go Set a Watchman was the novel Harper Lee first submitted to her publishers before To Kill a Mockingbird. Assumed to have been lost, the manuscript was discovered in late 2014." + } + ] + }, + { + "id":"bestseller", + "name":"Best seller", + "items":[ + { + "id":5, + "name":"First 100 Words ", + "cover":"http://ecx.images-amazon.com/images/I/51dxds64%2ByL.jpg", + "intro":"Your little one will soon learn some essential first words and pictures with this bright board book. There are 100 color photographs to look at and talk about, and 100 simple first words to read and learn, too. The pages are made from tough board for hours of fun reading, and the cover is softly padded for little hands to hold." + }, + + { + "id":6, + "name":"The Girl on the Train ", + "cover":"http://ecx.images-amazon.com/images/I/516YNFvZnrL.jpg", + "intro":"“The Girl on the Train has more fun with unreliable narration than any chiller since Gone Girl. . . . [It] is liable to draw a large, bedazzled readership.”—The New York Times" + }, + + { + "id":7, + "name":"The English Spy", + "cover":"http://ecx.images-amazon.com/images/I/51dAriB850L.jpg", + "intro":"#1 New York Times bestselling author Daniel Silva delivers another stunning thriller in his latest action-packed tale of high stakes international intrigue featuring the inimitable Gabriel Allon." + } + ] + }, + { + "id":"special", + "name":"Special", + "items":[ + { + "id":8, + "name":"Homeworld (Odyssey One) ", + "cover":"http://ecx.images-amazon.com/images/I/51SVZ%2BFqUrL.jpg", + "intro":"The consequences of Earth’s exploration of the Galaxy come home to roost when the Drasin track a human ship back to Earth. Mounting a desperate defense, the crew of the NAC spacecraft Odyssey, their allies, and the people of Earth face an overwhelming force of invading alien ships wielding terrible power. Doomed from the start, but with nowhere to retreat, Captain Eric Weston commits his ship to the defense of the human race even as the human outposts in Sol system fall one by one before the unrelenting Drasin onslaught." + }, + + { + "id":9, + "name":"The Fire of Home (A Powell Springs Novel)", + "cover":"http://ecx.images-amazon.com/images/I/514WiN2ax%2BL.jpg", + "intro":"When Amy Layton’s family learned she planned to steal her sister’s fiancé, Amy left home in disgrace. But in 1922, she returns to Powell Springs to escape the violent man she married. Despite the town’s gossip, Amy is determined to rebuild her shattered life with the boardinghouse she inherited…and little else." + }, + + { + "id":10, + "name":"Home by Morning (A Powell Springs Novel) ", + "cover":"http://ecx.images-amazon.com/images/I/51e03IxwdJL.jpg", + "intro":"October 1918: En route from New York to Seattle, Jessica Layton stops for a visit in her hometown of Powell Springs, Oregon, and comes face-to-face with Cole Braddock, her first and only love from years ago. Now Jessica is a highly accomplished clinical physician preparing for an exciting new job in Washington, and Cole is a successful horse breeder who is courting her sister Amy. Both are convinced they have moved beyond their youthful passion and the heartbreak it produced; " + } + ] + }, + { + "id":"all", + "name":"All", + "items":[] + } +] \ No newline at end of file diff --git a/example/styles/bookstore.css b/example/styles/bookstore.css new file mode 100644 index 0000000..1da922f --- /dev/null +++ b/example/styles/bookstore.css @@ -0,0 +1,64 @@ +#navMenu ul{ + list-style: none; + border: lightgray 1px solid; + border-radius: 5px; + padding: 0; +} +#navMenu li{ + border-right: lightgray 1px solid; + display: inline-block; + padding: 4px 10px; + text-align: center; + min-width: 150px; + cursor: pointer; +} +#navMenu li:hover{ + background-color: #e0e0ff; +} + +#navMenu .selected{ + background-color: #0381ff; + color:white; +} +#navMenu .selected:hover{ + background-color: #0371ee; +} +#navMenu li:last-child{ + border-right: none; +} + +#booksList{ + height:600px; + overflow: auto; +} +#booksList li{ + padding: 5px; + cursor: pointer; +} +#booksList li:hover{ + background-color: #e0e0ff; +} + +#booksList li>div{ + display: inline-block; + height: 80px; + line-height: 80px; + vertical-align: middle; +} +#booksList li>img{ + width: 60px; + height: 80px; + display: inline-block; + vertical-align: middle; +} + +#bookDetails >img{ + width: 150px; + height: 200px; +} +#bookDetails{ + max-width: 500px; +} +#bookDetails button{ + padding: 5px 10px; +} \ No newline at end of file diff --git a/src/core/HTMLKnotBuilder.js b/src/core/HTMLKnotBuilder.js index efdb846..0efa373 100644 --- a/src/core/HTMLKnotBuilder.js +++ b/src/core/HTMLKnotBuilder.js @@ -176,6 +176,7 @@ //apply CBS to node. parse the CBS options as well as the in-html options and store the result //on node.__knot.options function applyCBSForNode(node) { + var cbsOptions = null; if(node.__knot && node.__knot.cbsOptions) { cbsOptions = node.__knot.cbsOptions; @@ -209,15 +210,30 @@ } } } - - for(var i=0; i< node.children.length; i++) { - applyCBSForNode(node.children[i]); + if(node.children){ + for(var i=0; i< node.children.length; i++) { + applyCBSForNode(node.children[i]); + } } } //use select to attach the CBS to the relevant nodes. the CBS is attached to node.__knot.cbsOption for further reference + + function processCBSForGlobalObject(selector, cbs) { + if (!knotsOptionsForGlobalObjects[selector]) { + knotsOptionsForGlobalObjects[selector] = {options:[]}; + } + for (var i = 0; i < cbs[selector].length; i++) { + knotsOptionsForGlobalObjects[selector].options = knotsOptionsForGlobalObjects[selector].options.concat(__private.OptionParser.parse(cbs[selector][i])); + } + } + function attachCBS(scope, cbs) { + var i; for(var selector in cbs) { + if(__private.Utility.startsWith(selector, "/")){ + processCBSForGlobalObject(selector, cbs); + } var elements; try { @@ -230,7 +246,7 @@ if(elements.length === 0) { __private.Log.warning("There is no element selected with selector:" + selector); } - for(var i=0; i", left:true, right:false}, + {splitter:"<=", left:false, right:true}, + {splitter:"=", left:true, right:true} + ]; + var __private = global.Knot.getPrivateScope(); //create embedded functions with the text //embedded functions are registered to Global Symbol @@ -63,8 +69,15 @@ return null; } - var parts = __private.Utility.splitWithBlockCheck(text, ":"); - if(parts.length !== 2) { + var parts, valueDirection; + for(var i=0; i< _valueDirection.length; i++){ + parts = __private.Utility.splitWithBlockCheck(text, _valueDirection[i].splitter); + if(parts.length === 2){ + valueDirection = _valueDirection[i]; + break; + } + } + if(!valueDirection){ __private.Log.error("Invalid option:"+text); return null; } @@ -76,6 +89,18 @@ return null; } + if(valueDirection.left){ + if(!left.options){ + left.options = {}; + } + left.options.readonly = "1"; + } + if(valueDirection.right){ + if(!right.options){ + right.options = {}; + } + right.options.readonly = "1"; + } return {leftAP:left, rightAP:right}; }, diff --git a/src/core/PrivateScope.js b/src/core/PrivateScope.js index 88ad041..41e36e8 100644 --- a/src/core/PrivateScope.js +++ b/src/core/PrivateScope.js @@ -7,6 +7,9 @@ //private scope of knot.js var __private = {}; + //knot variants, can be accessed by Utility.getValueOnPath with prefix "$" + __private.KnotVariants = {}; + __private.Setting = { enablePropertyHook: true }; diff --git a/src/core/Utility.js b/src/core/Utility.js index 5cb4793..e28890a 100644 --- a/src/core/Utility.js +++ b/src/core/Utility.js @@ -62,6 +62,10 @@ data= global; path = path.substr(1); } + else if(path[0] === "$"){ + data = __private.KnotVariants; + path = path.substr(1); + } while (path.indexOf(".") >= 0 && data) { var p = __private.Utility.trim(path.substr(0, path.indexOf("."))); if(p !== "*") { @@ -99,6 +103,10 @@ data = global; path = path.substr(1); } + else if(path[0] === "$"){ + data = __private.KnotVariants; + path = path.substr(1); + } var vp = path; var p = path.lastIndexOf("."); @@ -169,7 +177,7 @@ var res = []; var blockStack = []; - + var splitterLength = splitter.length; while(pos < str.length) { if(_blockStartMarks[str[pos]]){ blockStack.push(str[pos]); @@ -181,9 +189,10 @@ blockStack.push(b); } } - else if(str[pos] === splitter && blockStack.length === 0){ + else if(blockStack.length === 0 && + str[pos] === splitter[0] && str.substr(pos, splitterLength) === splitter){ res.push(str.substr(prev, pos-prev)); - prev = pos+1; + prev = pos+splitterLength; } pos++; } diff --git a/src/core/WindowHashStatus.js b/src/core/WindowHashStatus.js new file mode 100644 index 0000000..25a6044 --- /dev/null +++ b/src/core/WindowHashStatus.js @@ -0,0 +1,114 @@ +(function (window) { + "use strict"; + var __private = window.Knot.getPrivateScope(); + + var _hashFields; + var _fieldSplitter; + + function getHash(){ + if(window.location.hash) { + return window.location.hash.substr(1); + } + else { + return ""; + } + } + + var _isInUpdateHash = false; + function updateHash(){ + if(_isInUpdateHash){ + return; + } + _isInUpdateHash = true; + try{ + if(_hashFields){ + var r= ""; + var values = _hashFields.map(function(t){return __private.Utility.getValueOnPath(null, "$hash." + t);}); + //remove the empty value at the end + for(var i=values.length-1; i>=0; i--){ + if(values[i]){ + break; + } + values.length = i; + } + var value = ""; + if(values.length > 0){ + value = values.join(_fieldSplitter); + } + window.location.hash = "#" + value; + __private.Utility.setValueOnPath(null, "$hash.hash", value); + } + } + finally{ + _isInUpdateHash = false; + } + } + + + function updateHashVariant(){ + if(_isInUpdateHash){ + return; + } + _isInUpdateHash = true; + try{ + var hash = getHash(); + if(_hashFields){ + var fields = __private.Utility.splitWithBlockCheck(hash, _fieldSplitter); + for(var i=0; i<_hashFields.length; i++){ + __private.Utility.setValueOnPath(null, "$hash."+_hashFields[i], fields[i]); + } + __private.Utility.setValueOnPath(null, "$hash.hash", hash); + } + else{ + __private.Utility.setValueOnPath(null, "$hash.hash", hash); + } + } + finally{ + _isInUpdateHash = false; + } + } + + __private.Utility.setValueOnPath(null, "$hash", {}); + var _hashObj = __private.Utility.getValueOnPath(null, "$hash"); + + updateHashVariant(); + + __private.WindowHashStatus = { + setHashFormat: function(fields, splitter){ + if(!(fields instanceof Array)){ + throw new Error("Hash fields must be an array."); + } + if(fields.indexOf("hash")>=0){ + throw new Error("Hash field can't be 'hash'."); + } + if(!splitter){ + throw new Error("Please specify the splitter."); + } + var i; + if(_hashFields){ + for(i=0; i< _hashFields.length; i++){ + __private.DataObserver.stopMonitoring(_hashObj, _hashFields[i], updateHash); + } + } + _hashFields = fields; + _fieldSplitter = splitter; + + if(_hashFields){ + for(i=0; i< _hashFields.length; i++){ + __private.DataObserver.monitor(_hashObj, _hashFields[i], updateHash); + } + } + updateHashVariant(); + } + }; + + __private.DataObserver.monitor(_hashObj, "hash", function(){ + updateHash(); + updateHashVariant(); + }); + + window.addEventListener("hashchange", function(){ + updateHashVariant(); + }); + +})(window); \ No newline at end of file diff --git a/src/debugger/debugger.cbs b/src/debugger/debugger.cbs index 9035aba..a571bb8 100644 --- a/src/debugger/debugger.cbs +++ b/src/debugger/debugger.cbs @@ -10,7 +10,7 @@ body{ @click:@{this.showLogViewer = true;} }; =>.page-headerArea>.header:last-child>span{ - className:highestLogLevel + className: highestLogLevel }; =>.page-headerArea>.header:first-child, .pageContent:first-child{ @@ -32,8 +32,8 @@ body{ }; =>.nodeTitle{ - text: description; - class:noKnotSetting>{return value?"+emptyNode":"";} + text = description; + class: noKnotSetting>{return value?"+emptyNode":"";} }; =>.highlightMark{ @@ -67,8 +67,8 @@ body{ .knotList>li{ =>.knotOption{ - text:description; - title:description + text= description; + title= description }; =>.knotValueDirection, .knotValue, .knotValueDetail{ @@ -90,7 +90,7 @@ body{ =>.errorStatusIndicator{ style.display:errorStatus>{return value?"inline-block":"none";}; - title:errorStatus>{return value?"Error message: "+ value.message:"";}; + title: errorStatus>{return value?"Error message: "+ value.message:"";}; }; } @@ -100,25 +100,25 @@ body{ foreach: knotChangeLog; =>.id{ - text: id + text = id }; =>.nodeTitle{ - text: nodeDescription; - title: nodeDescription + text = nodeDescription; + title = nodeDescription }; => .knotOption{ - text: knotOption.description; - title: knotOption.description; + text = knotOption.description; + title = knotOption.description; }; => .knotValueDirection{ - class:isFromLeftToRight>{return value?"+fa-long-arrow-right -fa-long-arrow-left":"-fa-long-arrow-right +fa-long-arrow-left";} + class = isFromLeftToRight>{return value?"+fa-long-arrow-right -fa-long-arrow-left":"-fa-long-arrow-right +fa-long-arrow-left";} }; => .knotValue{ - text: value>{return JSON.stringify(value);}; - title: value>{return JSON.stringify(value);}; + text = value>{return JSON.stringify(value);}; + title = value>{return JSON.stringify(value);}; }; => .knotValueDetail{ - @click:@/debuggerModel.onShowKnotValueLogDetail + @click: @/debuggerModel.onShowKnotValueLogDetail }; } @@ -151,7 +151,7 @@ body{ } .logTemplate{ - style.backgroundColor: level>{ + style.backgroundColor = level>{ switch(value){ case "Info": return "transparent"; @@ -163,21 +163,21 @@ body{ }; => .level{ - text:level + text = level }; => .time{ - text:time>{ + text = time>{ return value.getHours() + ":" + value.getMinutes() + ":" + value.getSeconds() + " " + value.getMilliseconds(); } }; => .message{ - text: message + text = message }; => .exception{ - text: exception>{return value.toString();} + text = exception>{return value.toString();} }; } diff --git a/src/debugger/debugger.js b/src/debugger/debugger.js index 99a1607..92f9e53 100644 --- a/src/debugger/debugger.js +++ b/src/debugger/debugger.js @@ -271,6 +271,10 @@ Knot.js debugger if(node.hasAttribute("knot-debugger-ignore")) { return; } + //when node is svg, there's no children. we don't support bind to svg at current stage + if(!node.children){ + return; + } var nodeInfo = { isExpanded:true, childrenInfo: [] @@ -284,7 +288,7 @@ Knot.js debugger } } - if(!node.__knot && nodeInfo.childrenInfo.length == 0) { + if(!node.__knot && nodeInfo.childrenInfo.length === 0) { return null; } diff --git a/test/HTMLKnotBuilder.test.js b/test/HTMLKnotBuilder.test.js index a64d0ca..c338828 100644 --- a/test/HTMLKnotBuilder.test.js +++ b/test/HTMLKnotBuilder.test.js @@ -317,7 +317,7 @@ var templateDiv = global.KnotTestUtility.parseHTML('
.
'); testDiv.appendChild(templateDiv); - var template2 = global.KnotTestUtility.parseHTML('