├── .gitignore ├── EBookPriceForDouBan ├── .gitignore ├── background.html ├── img │ ├── books128.gif │ ├── books16.gif │ ├── books38.jpg │ └── books48.png ├── js │ ├── binder.js │ ├── dependencies │ │ ├── jquery-1.8.2.js │ │ └── knockout-latest.debug.js │ ├── injecter.js │ ├── launcher.js │ ├── searchers.js │ └── searchers │ │ ├── amazonSearcher.js │ │ ├── dangdangSearcher.js │ │ ├── duokanSearcher.js │ │ ├── jingdongSearcher.js │ │ ├── koboSearcher.js │ │ ├── nookSearcher.js │ │ ├── tangchaSearcher.js │ │ ├── taobaoSearcher.js │ │ └── utils.js └── manifest.json ├── FizzBuzz ├── FizzBuzz.js ├── FizzBuzzRunner.html ├── FizzBuzzSpec.js └── FizzBuzzUITest.html ├── README.md ├── RemoveItemsLambda ├── RemoveItemsLambda.js ├── RemoveItemsLambdaRunner.html └── RemoveItemsLambdaSpec.js ├── RunnerTemplate.html ├── TryAngular ├── Try1 │ └── Try1.html └── Try2 │ ├── Try2.html │ ├── todo.css │ └── todo.js ├── TryKnockout ├── EMail.html ├── EMail.js ├── Premium │ ├── Premium.html │ └── Premium.js ├── SimpleViewModel.html ├── SimpleViewModel.js ├── TWBooks │ ├── .idea │ │ ├── .name │ │ ├── TWBooks.iml │ │ ├── encodings.xml │ │ ├── libraries │ │ │ └── sass_stdlib.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── scopes │ │ │ └── scope_settings.xml │ │ └── vcs.xml │ ├── Books.html │ ├── Books.js │ ├── BooksData.js │ ├── StringSimilarity.js │ └── knockout-latest.debug.js ├── UsingList.html ├── UsingList.js ├── knockout-latest.debug.js ├── ko.tmproj └── web-server.js ├── TryRequireJs ├── jquery-1.8.2.js ├── myPage.html ├── scripts │ ├── main.js │ ├── require.js │ ├── subDir1 │ │ └── util1.js │ └── subDir2 │ │ └── util2.js └── stick_price_tmp.js ├── dropdowndemo ├── css │ └── bootstrap.css ├── dropdowndemo.html └── js │ ├── bootstrap.js │ └── jquery.js └── lib └── jasmine-1.2.0 ├── MIT.LICENSE ├── jasmine-html.js ├── jasmine.css └── jasmine.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | RemoveItemsLambda/.DS_Store 3 | 4 | TryAngular/Try1/.DS_Store 5 | 6 | .DS_Store 7 | TryAngular 8 | 9 | .idea/libraries/sass_stdlib.xml 10 | 11 | TryKnockout/TWBooks/.idea/workspace.xml 12 | 13 | .idea/scopes/scope_settings.xml 14 | 15 | .idea/workspace.xml 16 | 17 | TryKnockout/TWBooks/.idea/workspace.xml 18 | 19 | *.iml 20 | 21 | .idea/encodings.xml 22 | 23 | .idea/misc.xml 24 | 25 | .idea/modules.xml 26 | 27 | .idea/vcs.xml 28 | 29 | TryKnockout/TWBooks/.idea/workspace.xml 30 | 31 | TryKnockout/TWBooks/.idea/workspace.xml 32 | 33 | TryKnockout/TWBooks/.idea/workspace.xml 34 | -------------------------------------------------------------------------------- /EBookPriceForDouBan/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /EBookPriceForDouBan/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /EBookPriceForDouBan/img/books128.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuipengfei/JavaScript-Practice-Code/265c736f9475029d92600d80035d9b6c11811713/EBookPriceForDouBan/img/books128.gif -------------------------------------------------------------------------------- /EBookPriceForDouBan/img/books16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuipengfei/JavaScript-Practice-Code/265c736f9475029d92600d80035d9b6c11811713/EBookPriceForDouBan/img/books16.gif -------------------------------------------------------------------------------- /EBookPriceForDouBan/img/books38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuipengfei/JavaScript-Practice-Code/265c736f9475029d92600d80035d9b6c11811713/EBookPriceForDouBan/img/books38.jpg -------------------------------------------------------------------------------- /EBookPriceForDouBan/img/books48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuipengfei/JavaScript-Practice-Code/265c736f9475029d92600d80035d9b6c11811713/EBookPriceForDouBan/img/books48.png -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/binder.js: -------------------------------------------------------------------------------- 1 | function bindSearchResultsToTemplate(searchResults) { 2 | ko.observableArray(searchResults); 3 | ko.applyBindings({searchResults: searchResults}); 4 | } -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/injecter.js: -------------------------------------------------------------------------------- 1 | function injectEmptyTemplate() { 2 | var htmlTemplate = '
' + 3 | '' + 21 | '
' + 22 | '
' + 23 | '
  • 支付宝扫码,打赏作者
  • ' + 24 | '' + 25 | '
    ' + 26 | '
    ' + 27 | '
    '; 28 | 29 | $(".gray_ad").first().append($(htmlTemplate)); 30 | } -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/launcher.js: -------------------------------------------------------------------------------- 1 | injectEmptyTemplate(); 2 | var searchResults = searchForEBooks(); 3 | bindSearchResultsToTemplate(searchResults); -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers.js: -------------------------------------------------------------------------------- 1 | function SearchResult(provider, price, url, currencyType) { 2 | this.provider = provider; 3 | this.price = price; 4 | this.url = url; 5 | this.description = provider + ":" + price + (currencyType ? currencyType : "元"); 6 | this.isPriceInNumber = !isNaN(price); 7 | } 8 | //todo: remove useless idx function params; fix nook problem when it has both paperbook and ebook. 9 | var searchers = [ 10 | duokanSearcher, 11 | tangchaSearcher, 12 | amazonSearcher, 13 | //taobaoSearcher,//fuck taobao gbk 14 | jingdongSearcher, 15 | dangdangSearcher, 16 | nookSearcher, 17 | koboSearcher 18 | ]; 19 | 20 | function doubanBookId() { 21 | var urlFragments = location.pathname.split("/"); 22 | return urlFragments[urlFragments.length - 2]; 23 | } 24 | 25 | function searchForEBooks() { 26 | var searchResults = ko.observableArray(); 27 | 28 | $.ajax({ 29 | url: "https://api.douban.com/v2/book/" + doubanBookId(), success: function (data) { 30 | var jsonResult = data; 31 | 32 | var bookTitle = jsonResult.title; 33 | var author = jsonResult.author[0]; 34 | var isbn = jsonResult.isbn13; 35 | 36 | $.each(searchers, function (index, searcher) { 37 | //we give all parameters to every searcher, it's up to the searcher to decide whether to use them or ignore them. 38 | searcher.search({title: bookTitle, author: author, isbn: isbn, searchResults: searchResults}); 39 | }); 40 | } 41 | }); 42 | 43 | return searchResults; 44 | } 45 | -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/amazonSearcher.js: -------------------------------------------------------------------------------- 1 | var amazonSearcher = { 2 | search: function (searchParameter) { 3 | var isbn = searchParameter.isbn; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | var twoSites = [ 7 | { 8 | searchUrl: "http://www.amazon.cn/s/ref=nb_sb_noss?url=node%3D116169071&field-keywords=" + isbn, 9 | name: "亚马逊(中国站)Kindle", 10 | currency: "元" 11 | }, 12 | { 13 | searchUrl: "http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Ddigital-text&field-keywords=" + isbn, 14 | name: "亚马逊(美国站)Kindle", 15 | currency: "美元" 16 | } 17 | ]; 18 | 19 | $.each(twoSites, function (inx, site) { 20 | $.ajax({ 21 | url: site.searchUrl, async: true, success: function (data) { 22 | var page = $(data); 23 | var resultsDiv = page.find("#resultsCol"); 24 | var noResultsTip = page.find("#noResultsTitle"); 25 | if (resultsDiv.length > 0 && noResultsTip.length == 0) { 26 | var price = resultsDiv.find(".a-color-price").first().text().replace("¥", "").replace("$", ""); 27 | var url = resultsDiv.find(".s-access-detail-page").attr("href"); 28 | searchResults.push(new SearchResult(site.name, price, url, site.currency)); 29 | } 30 | } 31 | }); 32 | }); 33 | } 34 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/dangdangSearcher.js: -------------------------------------------------------------------------------- 1 | var dangdangSearcher = { 2 | search: function (searchParameter) { 3 | var isbn = searchParameter.isbn; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | var url = "http://search.dangdang.com/?key=" + isbn + "&category_path=98.00.00.00.00.00&type=98.00.00.00.00.00"; 7 | 8 | $.ajax({ 9 | url: url, async: true, success: function (data) { 10 | var page = $(data); 11 | if (isFound(page)) { 12 | var book = parseBookFrom(page); 13 | searchResults.push(new SearchResult("当当电子书", book.price, book.url)); 14 | } 15 | } 16 | }); 17 | 18 | function parseBookFrom(page) { 19 | var bookLi = $(page.find(".bigimg").find("li").first()); 20 | var url = bookLi.find("a").attr("href"); 21 | var price = bookLi.find(".search_now_price").text().replace("¥", ""); 22 | return {url: url, price: price}; 23 | } 24 | 25 | function isFound(page) { 26 | var notFound = page.find(".no_result_tips"); 27 | return notFound.length === 0; 28 | } 29 | } 30 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/duokanSearcher.js: -------------------------------------------------------------------------------- 1 | var duokanSearcher = { 2 | search: function (searchParameter) { 3 | var title = searchParameter.title; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | var duokanSearchUrl = "http://book.duokan.com/store/v0/web/search?s=" + title; 7 | var duokanBookUrlTemplate = "http://www.duokan.com/book/"; 8 | 9 | $.ajax({ 10 | url: duokanSearchUrl, async: true, success: function (response) { 11 | var matchedBook = response.items.filter(function (item) { 12 | return item.title.indexOf(title) != -1 || title.indexOf(item.title) != -1; 13 | })[0]; 14 | if (matchedBook) { 15 | var url = duokanBookUrlTemplate + matchedBook.sid; 16 | var price = matchedBook.new_price != undefined ? matchedBook.new_price : matchedBook.price; 17 | searchResults.push(new SearchResult("多看阅读", price, url)); 18 | } 19 | } 20 | }); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/jingdongSearcher.js: -------------------------------------------------------------------------------- 1 | var jingdongSearcher = { 2 | search: function (searchParameter) { 3 | var isbn = searchParameter.isbn; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | var jingdongSearchUrl = "http://search.e.jd.com/searchDigitalBookAjax?ajaxSearch=1&key=" + isbn; 7 | 8 | $.ajax({ 9 | url: jingdongSearchUrl, async: true, dataType: "json", success: function (jsonResult) { 10 | if (jsonResult) { 11 | var wareID = jsonResult.Paragraph[0].wareid; 12 | 13 | var url = "http://e.jd.com/" + wareID + ".html"; 14 | var price = jsonResult.Paragraph[0].hprice / 100; 15 | 16 | var jingdongSearchResult = new SearchResult("京东电子书", price, url); 17 | searchResults.push(jingdongSearchResult); 18 | } 19 | } 20 | }); 21 | } 22 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/koboSearcher.js: -------------------------------------------------------------------------------- 1 | var koboSearcher = { 2 | search: function (searchParameter) { 3 | var searchResults = searchParameter.searchResults; 4 | 5 | function searchWithMatchingISBN(matchingISBN) { 6 | var koboSearchUrl = "http://www.kobobooks.com/search/search.html?q=" + matchingISBN; 7 | 8 | $.ajax({ 9 | url: koboSearchUrl, async: true, success: function (data) { 10 | var page = $(data); 11 | var notFoundMsg = page.find("ctl00_ctl00_ctl00_Body_Body_ContentBody_liNoResults"); 12 | var priceTag = page.find(".KV2OurPrice"); 13 | 14 | if (notFoundMsg.length === 0 && priceTag.length > 0) { 15 | var price = priceTag.find("strong").text().replace("$", ""); 16 | var url = koboSearchUrl; 17 | 18 | var koboSearchResult = new SearchResult("Kobo电子书", price, url, "美元"); 19 | searchResults.push(koboSearchResult); 20 | } 21 | } 22 | }); 23 | } 24 | 25 | //kobo only sells ebook, and different from amazon and nook, searching with the paper book's ISBN does not work with kobo 26 | //so we have to find the paper book's counterpart from google and then seatch kobo 27 | getMatchingISBNsFromGoogle(searchParameter.title, searchParameter.author, searchWithMatchingISBN); 28 | } 29 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/nookSearcher.js: -------------------------------------------------------------------------------- 1 | var nookSearcher = { 2 | search: function (searchParameter) { 3 | var isbn = searchParameter.isbn; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | function searchWithISBN(isbn) { 7 | var nookSearchUrl = "http://www.barnesandnoble.com/s?keyword=" + isbn + "&store=ebook"; 8 | $.ajax({ 9 | url: nookSearchUrl, async: true, success: function (data) { 10 | var page = $(data); 11 | var notFoundMsg = page.find("#search-noresults-message-1"); 12 | var nookDiv = page.find("#nook-price-1"); 13 | if (notFoundMsg.length === 0 && nookDiv.length > 0) { 14 | var priceTag = nookDiv.find(".price"); 15 | var price = priceTag.text().replace("$", ""); 16 | var url = nookSearchUrl; 17 | var nookSearchResult = new SearchResult("Nook电子书", price, url, "美元"); 18 | searchResults.push(nookSearchResult); 19 | } 20 | //sometimes nook barnes and noble has both ebook and paper book, searching with the paper books isbn 21 | //directly return the paperbook 22 | //so we need to find the paper book's ebook counterpart from google and search again. 23 | else { 24 | getMatchingISBNsFromGoogle(searchParameter.title, searchParameter.author, function (matchingISBN) { 25 | searchWithISBN(matchingISBN); 26 | }); 27 | } 28 | } 29 | }); 30 | } 31 | 32 | searchWithISBN(isbn); 33 | } 34 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/tangchaSearcher.js: -------------------------------------------------------------------------------- 1 | var tangchaSearcher = { 2 | search: function (searchParameter) { 3 | var title = searchParameter.title; 4 | var searchResults = searchParameter.searchResults; 5 | var tangchaSearchUrl = "http://tangcha.tc/books/search/" + title + ".jsd"; 6 | var tangchaBookUrlTemplate = "http://tangcha.tc/"; 7 | 8 | $.ajax({ 9 | url: tangchaSearchUrl, async: true, success: function (data) { 10 | eval(data); 11 | var div = $(html); 12 | var firstMatch = div.find("a").filter(function (index, a) { 13 | return $(a).attr("href").indexOf("books") != -1 && $(a).attr("href").indexOf("search") == -1; 14 | }).first(); 15 | if (firstMatch.length > 0) { 16 | var bookUrl = tangchaBookUrlTemplate + firstMatch.attr("href"); 17 | $.ajax({ 18 | url: bookUrl, async: false, success: function (bookData) { 19 | var section = $(bookData); 20 | var price = section.find(".book-purchase").text(); 21 | 22 | var tangchaSearchResult = new SearchResult("唐茶", price.replace("¥", ""), bookUrl.replace(".jsd", "")); 23 | searchResults.push(tangchaSearchResult); 24 | } 25 | }); 26 | } 27 | } 28 | }); 29 | } 30 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/taobaoSearcher.js: -------------------------------------------------------------------------------- 1 | var taobaoSearcher = { 2 | search: function (searchParameter) { 3 | var title = searchParameter.title; 4 | var searchResults = searchParameter.searchResults; 5 | 6 | var taobaoSearchUrl = "http://shuzi.taobao.com/item/search.htm?q=" + encodeURIComponent(title) + "&isbook=ebook"; 7 | 8 | $.ajax({ 9 | url: taobaoSearchUrl, async: true, success: function (data) { 10 | var page = $(data); 11 | var resultList = page.find(".resultlist_pic.clr"); 12 | var errorDiv = page.find(".msgBox.w758b1.mt10"); 13 | if (errorDiv.length == 0) { 14 | var url = resultList.find("a").attr("href"); 15 | var price = resultList.find(".hotbox_price").find("span").text() 16 | 17 | var taobaoSearchResult = new SearchResult("淘宝电子书", price, url); 18 | searchResults.push(taobaoSearchResult); 19 | } 20 | } 21 | }); 22 | } 23 | }; -------------------------------------------------------------------------------- /EBookPriceForDouBan/js/searchers/utils.js: -------------------------------------------------------------------------------- 1 | function getMatchingISBNsFromGoogle(title, author, callBack) { 2 | 3 | var googleBookSearchUrl = "https://www.googleapis.com/books/v1/volumes?q=" + title + "+inauthor:" + author; 4 | $.ajax({ 5 | url: googleBookSearchUrl, async: true, success: function (googleResultJson) { 6 | var matchingISBNs = googleResultJson.items.filter(function (item) { 7 | return item.volumeInfo.title === title; 8 | }).map(function (item) { 9 | return item.volumeInfo.industryIdentifiers[1].identifier; 10 | }); 11 | if (matchingISBNs.length > 0) { 12 | $.each(matchingISBNs, function (idx, matchingISBN) { 13 | callBack(matchingISBN); 14 | }); 15 | } 16 | } 17 | }); 18 | } -------------------------------------------------------------------------------- /EBookPriceForDouBan/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "豆瓣电子书比价", 4 | "description": "本插件帮您在浏览豆瓣上的书目时找到该书的电子版(正版,需付费)。现支持多看,亚马逊,京东,亚马逊,当当。", 5 | "version": "1.13", 6 | "background": { 7 | "persistent": false, 8 | "page": "background.html" 9 | }, 10 | "icons": { 11 | "16": "img/books16.gif", 12 | "48": "img/books48.png", 13 | "128": "img/books128.gif" 14 | }, 15 | "content_scripts": [ 16 | { 17 | "matches": ["http://book.douban.com/subject/*"], 18 | "js": [ 19 | "js/dependencies/jQuery-1.8.2.js", 20 | "js/dependencies/knockout-latest.debug.js", 21 | "js/injecter.js", 22 | "js/searchers/utils.js", 23 | "js/searchers/duokanSearcher.js", 24 | "js/searchers/tangchaSearcher.js", 25 | "js/searchers/amazonSearcher.js", 26 | "js/searchers/taobaoSearcher.js", 27 | "js/searchers/jingdongSearcher.js", 28 | "js/searchers/dangdangSearcher.js", 29 | "js/searchers/nookSearcher.js", 30 | "js/searchers/koboSearcher.js", 31 | "js/searchers.js", 32 | "js/binder.js", 33 | "js/launcher.js" 34 | ] 35 | } 36 | ], 37 | "permissions": [ 38 | "http://book.duokan.com/", 39 | "http://tangcha.tc/", 40 | "http://www.amazon.cn/", 41 | "http://www.amazon.com/", 42 | "http://shuzi.taobao.com/", 43 | "http://search.e.jd.com/", 44 | "http://search.dangdang.com/", 45 | "http://www.barnesandnoble.com/", 46 | "http://search.barnesandnoble.com/", 47 | "http://www.kobobooks.com/", 48 | "https://www.googleapis.com/", 49 | "https://api.douban.com/" 50 | ], 51 | "page_action": { 52 | "default_icon": { 53 | "38": "img/books38.jpg" 54 | }, 55 | "default_title": "EBook Price" 56 | } 57 | } -------------------------------------------------------------------------------- /FizzBuzz/FizzBuzz.js: -------------------------------------------------------------------------------- 1 | function fizzBuzz (number) 2 | { 3 | var fizz = number % 3 == 0; 4 | var buzz = number % 5 == 0; 5 | 6 | if(fizz && buzz){return "fizz buzz";} 7 | if(fizz){return "fizz";} 8 | if(buzz){return "buzz";} 9 | 10 | return number; 11 | } -------------------------------------------------------------------------------- /FizzBuzz/FizzBuzzRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner for FizzBuzz 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /FizzBuzz/FizzBuzzSpec.js: -------------------------------------------------------------------------------- 1 | describe("Fizz Buzz",function(){ 2 | it("should say fizz when passing in 3",function(){ 3 | var result = fizzBuzz(3); 4 | expect(result).toEqual("fizz"); 5 | }); 6 | 7 | it("should say buzz when passing in 5",function(){ 8 | var result = fizzBuzz(5); 9 | expect(result).toEqual("buzz"); 10 | }); 11 | 12 | it("should say fizz buzz when passing in 15",function(){ 13 | var result = fizzBuzz(15); 14 | expect(result).toEqual("fizz buzz"); 15 | }); 16 | 17 | it("should say 17 when passing in 17",function(){ 18 | var result = fizzBuzz(17); 19 | expect(result).toEqual(17); 20 | }); 21 | 22 | it("should say the number itself when passing in a number that's can not be divided by neither 2 nor 5",function(){ 23 | var numbers = [1, 2, 4, 7, 8, 11, 13, 14, 16, 17, 19]; 24 | for (var i=0; i < numbers.length; i++) { 25 | var number = numbers[i]; 26 | var result = fizzBuzz(number); 27 | expect(result).toEqual(number); 28 | }; 29 | }); 30 | }); -------------------------------------------------------------------------------- /FizzBuzz/FizzBuzzUITest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | fizz buzz 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JavaScript-Practice-Code 2 | ======================== 3 | 4 | JS code 5 | push test -------------------------------------------------------------------------------- /RemoveItemsLambda/RemoveItemsLambda.js: -------------------------------------------------------------------------------- 1 | function removeItemsFromArrayBase(rule) { 2 | return function(array) { 3 | return array.filter(function(i) { 4 | return rule(i); 5 | }); 6 | }; 7 | } 8 | 9 | var removeNumbersBiggerThan5 = removeItemsFromArrayBase(function(i) { 10 | return i < 5; 11 | }); 12 | 13 | var removeOddNumbers = removeItemsFromArrayBase(function(i) { 14 | return i % 2 == 0; 15 | }); 16 | 17 | var removeApples = removeItemsFromArrayBase(function(i) { 18 | return i != "apple"; 19 | }); 20 | -------------------------------------------------------------------------------- /RemoveItemsLambda/RemoveItemsLambdaRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner for FizzBuzz 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /RemoveItemsLambda/RemoveItemsLambdaSpec.js: -------------------------------------------------------------------------------- 1 | describe("remove numbers bigger than 5", function() { 2 | it("should remove 6789 from 123456789", function() { 3 | var result = removeNumbersBiggerThan5([1, 2, 3, 4, 5, 6, 7, 8, 9]); 4 | 5 | expect(result).toContain(1); 6 | expect(result).toContain(2); 7 | expect(result).toContain(3); 8 | expect(result).toContain(4); 9 | 10 | expect(result).not.toContain(5); 11 | expect(result).not.toContain(6); 12 | expect(result).not.toContain(7); 13 | expect(result).not.toContain(8); 14 | expect(result).not.toContain(9); 15 | }); 16 | }); 17 | 18 | describe("remove odd numbers", function() { 19 | it("should remove 135 from 123456", function() { 20 | var result = removeOddNumbers([1, 2, 3, 4, 5, 6]); 21 | 22 | expect(result).toContain(2); 23 | expect(result).toContain(4); 24 | expect(result).toContain(6); 25 | 26 | expect(result).not.toContain(1); 27 | expect(result).not.toContain(3); 28 | expect(result).not.toContain(5); 29 | }); 30 | }); 31 | 32 | describe("remove apples", function() { 33 | it("should remove apples 1apple2apple3", function() { 34 | var result = removeApples(["1", "apple", "2", "apple", "3"]); 35 | 36 | expect(result).toContain("1"); 37 | expect(result).toContain("2"); 38 | expect(result).toContain("3"); 39 | 40 | expect(result).not.toContain("apple"); 41 | }); 42 | }); 43 | 44 | describe("removeItemsFromArrayBase", function() { 45 | it("should return a function", function() { 46 | var result = removeItemsFromArrayBase(function(i){return true;}); 47 | 48 | expect(typeof result).toEqual("function"); 49 | }); 50 | }); -------------------------------------------------------------------------------- /RunnerTemplate.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner for FizzBuzz 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /TryAngular/Try1/Try1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 |
    11 |

    Hello {{yourName}}!

    12 |
    13 | 14 | -------------------------------------------------------------------------------- /TryAngular/Try2/Try2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

    My todo list

    10 |
    11 | {{remaining()}} of {{todos.length}} remaining 12 | [ archive ] 13 | 19 |
    20 | 22 | 23 |
    24 |
    25 | 26 | -------------------------------------------------------------------------------- /TryAngular/Try2/todo.css: -------------------------------------------------------------------------------- 1 | .done-true { 2 | text-decoration: line-through; 3 | color: grey; 4 | } -------------------------------------------------------------------------------- /TryAngular/Try2/todo.js: -------------------------------------------------------------------------------- 1 | function TodoController($scope) { 2 | $scope.todos = [{ 3 | text: 'item1', 4 | done: true 5 | }, { 6 | text: 'item2', 7 | done: false 8 | }]; 9 | 10 | $scope.addTodo = function() { 11 | $scope.todos.push({ 12 | text: $scope.todoText, 13 | done: false 14 | }); 15 | $scope.todoText = ''; 16 | }; 17 | 18 | $scope.remaining = function() { 19 | return getRemainingToDoItems().length; 20 | }; 21 | 22 | $scope.archive = function() { 23 | $scope.todos = getRemainingToDoItems(); 24 | }; 25 | 26 | function getRemainingToDoItems() { 27 | return $scope.todos.filter(function(item) { 28 | return !item.done 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TryKnockout/EMail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | using list 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
    FromToSubjectDate
    36 | 37 | 38 |
    39 |
    40 |

    41 |

    :

    42 |

    :

    43 |

    :

    44 |
    45 |

    46 |

    47 | 48 | -------------------------------------------------------------------------------- /TryKnockout/EMail.js: -------------------------------------------------------------------------------- 1 | function WebmailViewModel() { 2 | // Data 3 | var self = this; 4 | self.folders = ['Inbox', 'Archive', 'Sent', 'Spam']; 5 | 6 | self.chosenFolderId = ko.observable(); 7 | 8 | // Behaviours 9 | self.goToFolder = function(folder) { 10 | self.chosenFolderId(folder); 11 | //self.chosenMailData(null); // Stop showing a mail 12 | $.get('http://learn.knockoutjs.com/mail', { 13 | folder: folder 14 | }, self.chosenFolderData); 15 | 16 | }; 17 | 18 | self.goToMail = function(mail) { 19 | self.chosenFolderId(mail.folder); 20 | self.chosenFolderData(null); // hide folder 21 | $.get("http://learn.knockoutjs.com/mail", { 22 | mailId: mail.id 23 | }, self.chosenMailData); 24 | }; 25 | 26 | self.chosenFolderData = ko.observable(); 27 | self.chosenMailData = ko.observable(); 28 | // Show inbox by default 29 | self.goToFolder('Inbox'); 30 | }; 31 | 32 | function onload() { 33 | ko.applyBindings(new WebmailViewModel()); 34 | } 35 | -------------------------------------------------------------------------------- /TryKnockout/Premium/Premium.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | QSP 4 | 5 | 6 | 7 | 8 |

    Your Premium is: 9 |

    11 | 12 |

    Discount: 13 | 15 | 17 |

    18 | 19 |

    Campaign: 20 |

    12 |

    Last name:

    13 | 14 |

    Full name:

    15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TryKnockout/SimpleViewModel.js: -------------------------------------------------------------------------------- 1 | function AppViewModel() { 2 | this.firstName = ko.observable("Bert"); 3 | this.lastName = ko.observable("Bertington"); 4 | 5 | this.fullName = ko.computed(function() { 6 | return this.firstName() + " " + this.lastName(); 7 | }, this); 8 | 9 | this.capitalizeLastName = function() { 10 | var currentVal = this.lastName(); // Read the current value 11 | this.lastName(currentVal.toUpperCase()); // Write back a modified value 12 | }; 13 | } 14 | 15 | function clickEventHandler() { 16 | var model = new AppViewModel(); 17 | // Activates knockout.js 18 | ko.applyBindings(model); 19 | } 20 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/.name: -------------------------------------------------------------------------------- 1 | TWBooks -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/TWBooks.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/libraries/sass_stdlib.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $APPLICATION_HOME_DIR$/lib/webide.jar!/resources/html5-schema/html5.rnc 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/Books.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TW Books 5 | 6 | 7 | 8 | 9 | 24 | 25 | 26 |

    Which books are the most popular?

    27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 49 | 50 | 51 |
    Book nameHow many people bought this book?Who bought this book?
    39 |
      40 |
    • 41 |
    42 |
    45 |
      46 |
    • 47 |
    48 |
    52 | 53 | -------------------------------------------------------------------------------- /TryKnockout/TWBooks/Books.js: -------------------------------------------------------------------------------- 1 | var group = function (arr, by, initGroups) { 2 | function tryGetPerfectMatch() { 3 | var groupItem = initGroups.filter(function (grp) { 4 | return grp.groupNames.filter(function (grpN) { 5 | return grpN.groupName === key; 6 | }).length != 0; 7 | })[0]; 8 | return groupItem; 9 | } 10 | 11 | function tryGetFuzzyMatch() { 12 | groupItem = initGroups.filter(function (grp) { 13 | return levenshteinenator(grp.groupNames[0].groupName, key) === 1; 14 | })[0]; 15 | } 16 | 17 | function createNewGroup() { 18 | groupItem = {groupNames:[], groupItems:[]}; 19 | initGroups.push(groupItem); 20 | } 21 | 22 | for (var i = 0; i < arr.length; i++) { 23 | var item = arr[i]; 24 | var key = by(item); 25 | 26 | var perfectMatch = true; 27 | var groupItem = tryGetPerfectMatch(); 28 | 29 | if (!groupItem) { 30 | perfectMatch = false; 31 | tryGetFuzzyMatch(); 32 | } 33 | 34 | if (!groupItem) { 35 | createNewGroup(); 36 | } 37 | 38 | if (!perfectMatch) { 39 | groupItem.groupNames.push({groupName:key}); 40 | } 41 | 42 | groupItem.groupItems.push(item); 43 | } 44 | 45 | return initGroups; 46 | } 47 | 48 | function onload() { 49 | //prepare data 50 | (function () { 51 | booksDataArray.forEach(function (item) { 52 | item.BookName = item.BookName.replace(" ", ""); 53 | }); 54 | booksDataArray = booksDataArray.filter(function (item) { 55 | return item.BookName.length > 1; 56 | }); 57 | }()); 58 | 59 | var groups = []; 60 | group(booksDataArray, function (item) { 61 | return item.BookName; 62 | }, groups); 63 | 64 | groups.sort(function (grp1, grp2) { 65 | return grp2.groupItems.length - grp1.groupItems.length; 66 | }) 67 | 68 | ko.observableArray(groups); 69 | ko.applyBindings({groups:groups}); 70 | } -------------------------------------------------------------------------------- /TryKnockout/TWBooks/StringSimilarity.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2006. All Rights reserved. 4 | 5 | If you use this script, please email me and let me know, thanks! 6 | 7 | Andrew Hedges 8 | andrew (at) hedges (dot) name 9 | 10 | If you want to hire me to write JavaScript for you, see my resume. 11 | 12 | http://andrew.hedges.name/resume/ 13 | 14 | */ 15 | 16 | // calculate the Levenshtein distance between a and b, fob = form object, passed to the function 17 | levenshteinenator = function (a, b) { 18 | var cost; 19 | 20 | // get values 21 | 22 | var m = a.length; 23 | 24 | var n = b.length; 25 | 26 | // make sure a.length >= b.length to use O(min(n,m)) space, whatever that is 27 | if (m < n) { 28 | var c = a; 29 | a = b; 30 | b = c; 31 | var o = m; 32 | m = n; 33 | n = o; 34 | } 35 | 36 | var r = new Array(); 37 | r[0] = new Array(); 38 | for (var c = 0; c < n + 1; c++) { 39 | r[0][c] = c; 40 | } 41 | 42 | for (var i = 1; i < m + 1; i++) { 43 | r[i] = new Array(); 44 | r[i][0] = i; 45 | for (var j = 1; j < n + 1; j++) { 46 | cost = (a.charAt(i - 1) == b.charAt(j - 1)) ? 0 : 1; 47 | r[i][j] = minimator(r[i - 1][j] + 1, r[i][j - 1] + 1, r[i - 1][j - 1] + cost); 48 | } 49 | } 50 | 51 | return r[m][n]; 52 | } 53 | 54 | // return the smallest of the three values passed in 55 | minimator = function (x, y, z) { 56 | if (x < y && x < z) return x; 57 | if (y < x && y < z) return y; 58 | return z; 59 | } -------------------------------------------------------------------------------- /TryKnockout/UsingList.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | using list 4 | 5 | 6 | 7 | 8 |

    Your seat reservations ()

    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
    Passenger nameMealSurcharge
    Remove
    28 | 29 | 30 | 31 |

    32 | Total surcharge: $ 33 |

    34 | 35 | 36 | -------------------------------------------------------------------------------- /TryKnockout/UsingList.js: -------------------------------------------------------------------------------- 1 | // Class to represent a row in the seat reservations grid 2 | 3 | 4 | function SeatReservation(name, initialMeal) { 5 | var self = this; 6 | 7 | self.name = name; 8 | 9 | self.meal = ko.observable(initialMeal); 10 | 11 | self.formattedPrice = ko.computed(function() { 12 | var price = self.meal().price; 13 | return price ? "$" + price.toFixed(2) : "None"; 14 | }); 15 | } 16 | 17 | // Overall viewmodel for this screen, along with initial state 18 | 19 | 20 | function ReservationsViewModel() { 21 | var self = this; 22 | 23 | // Non-editable catalog data - would come from the server 24 | self.availableMeals = [{ 25 | mealName: "Standard (sandwich)", 26 | price: 0 27 | }, { 28 | mealName: "Premium (lobster)", 29 | price: 34.95 30 | }, { 31 | mealName: "Ultimate (whole zebra)", 32 | price: 290 33 | }]; 34 | 35 | // Editable data 36 | self.seats = ko.observableArray([ 37 | new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0])]); 38 | 39 | // Operations 40 | self.addSeat = function() { 41 | self.seats.push(new SeatReservation("new guy", self.availableMeals[1])); 42 | }; 43 | 44 | self.removeSeat = function(seat) { 45 | self.seats.remove(seat) 46 | }; 47 | 48 | self.totalSurcharge = ko.computed(function() { 49 | var total = 0; 50 | for (var i = 0; i < self.seats().length; i++) 51 | total += self.seats()[i].meal().price; 52 | return total; 53 | }); 54 | 55 | } 56 | 57 | function onload() { 58 | ko.applyBindings(new ReservationsViewModel()); 59 | } 60 | -------------------------------------------------------------------------------- /TryKnockout/ko.tmproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | currentDocument 6 | EMail.html 7 | documents 8 | 9 | 10 | expanded 11 | 12 | name 13 | TryKnockout 14 | regexFolderFilter 15 | !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ 16 | sourceDirectory 17 | 18 | 19 | 20 | fileHierarchyDrawerWidth 21 | 214 22 | metaData 23 | 24 | EMail.html 25 | 26 | caret 27 | 28 | column 29 | 74 30 | line 31 | 4 32 | 33 | firstVisibleColumn 34 | 0 35 | firstVisibleLine 36 | 1 37 | 38 | EMail.js 39 | 40 | caret 41 | 42 | column 43 | 21 44 | line 45 | 13 46 | 47 | columnSelection 48 | 49 | firstVisibleColumn 50 | 0 51 | firstVisibleLine 52 | 0 53 | selectFrom 54 | 55 | column 56 | 10 57 | line 58 | 13 59 | 60 | selectTo 61 | 62 | column 63 | 26 64 | line 65 | 13 66 | 67 | 68 | 69 | openDocuments 70 | 71 | EMail.html 72 | EMail.js 73 | 74 | showFileHierarchyDrawer 75 | 76 | windowFrame 77 | {{217, 4}, {1216, 874}} 78 | 79 | 80 | -------------------------------------------------------------------------------- /TryKnockout/web-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var sys = require('sys'), 4 | http = require('http'), 5 | fs = require('fs'), 6 | url = require('url'), 7 | events = require('events'); 8 | 9 | var DEFAULT_PORT = 8000; 10 | 11 | function main(argv) { 12 | new HttpServer({ 13 | 'GET': createServlet(StaticServlet), 14 | 'HEAD': createServlet(StaticServlet) 15 | }).start(Number(argv[2]) || DEFAULT_PORT); 16 | } 17 | 18 | function escapeHtml(value) { 19 | return value.toString(). 20 | replace('<', '<'). 21 | replace('>', '>'). 22 | replace('"', '"'); 23 | } 24 | 25 | function createServlet(Class) { 26 | var servlet = new Class(); 27 | return servlet.handleRequest.bind(servlet); 28 | } 29 | 30 | /** 31 | * An Http server implementation that uses a map of methods to decide 32 | * action routing. 33 | * 34 | * @param {Object} Map of method => Handler function 35 | */ 36 | function HttpServer(handlers) { 37 | this.handlers = handlers; 38 | this.server = http.createServer(this.handleRequest_.bind(this)); 39 | } 40 | 41 | HttpServer.prototype.start = function(port) { 42 | this.port = port; 43 | this.server.listen(port); 44 | sys.puts('Http Server running at http://localhost:' + port + '/'); 45 | }; 46 | 47 | HttpServer.prototype.parseUrl_ = function(urlString) { 48 | var parsed = url.parse(urlString); 49 | parsed.pathname = url.resolve('/', parsed.pathname); 50 | return url.parse(url.format(parsed), true); 51 | }; 52 | 53 | HttpServer.prototype.handleRequest_ = function(req, res) { 54 | var logEntry = req.method + ' ' + req.url; 55 | if (req.headers['user-agent']) { 56 | logEntry += ' ' + req.headers['user-agent']; 57 | } 58 | sys.puts(logEntry); 59 | req.url = this.parseUrl_(req.url); 60 | var handler = this.handlers[req.method]; 61 | if (!handler) { 62 | res.writeHead(501); 63 | res.end(); 64 | } else { 65 | handler.call(this, req, res); 66 | } 67 | }; 68 | 69 | /** 70 | * Handles static content. 71 | */ 72 | function StaticServlet() {} 73 | 74 | StaticServlet.MimeMap = { 75 | 'txt': 'text/plain', 76 | 'html': 'text/html', 77 | 'css': 'text/css', 78 | 'xml': 'application/xml', 79 | 'json': 'application/json', 80 | 'js': 'application/javascript', 81 | 'jpg': 'image/jpeg', 82 | 'jpeg': 'image/jpeg', 83 | 'gif': 'image/gif', 84 | 'png': 'image/png' 85 | }; 86 | 87 | StaticServlet.prototype.handleRequest = function(req, res) { 88 | var self = this; 89 | var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/, function(match, hex){ 90 | return String.fromCharCode(parseInt(hex, 16)); 91 | }); 92 | var parts = path.split('/'); 93 | if (parts[parts.length-1].charAt(0) === '.') 94 | return self.sendForbidden_(req, res, path); 95 | fs.stat(path, function(err, stat) { 96 | if (err) 97 | return self.sendMissing_(req, res, path); 98 | if (stat.isDirectory()) 99 | return self.sendDirectory_(req, res, path); 100 | return self.sendFile_(req, res, path); 101 | }); 102 | } 103 | 104 | StaticServlet.prototype.sendError_ = function(req, res, error) { 105 | res.writeHead(500, { 106 | 'Content-Type': 'text/html' 107 | }); 108 | res.write('\n'); 109 | res.write('Internal Server Error\n'); 110 | res.write('

    Internal Server Error

    '); 111 | res.write('
    ' + escapeHtml(sys.inspect(error)) + '
    '); 112 | sys.puts('500 Internal Server Error'); 113 | sys.puts(sys.inspect(error)); 114 | }; 115 | 116 | StaticServlet.prototype.sendMissing_ = function(req, res, path) { 117 | path = path.substring(1); 118 | res.writeHead(404, { 119 | 'Content-Type': 'text/html' 120 | }); 121 | res.write('\n'); 122 | res.write('404 Not Found\n'); 123 | res.write('

    Not Found

    '); 124 | res.write( 125 | '

    The requested URL ' + 126 | escapeHtml(path) + 127 | ' was not found on this server.

    ' 128 | ); 129 | res.end(); 130 | sys.puts('404 Not Found: ' + path); 131 | }; 132 | 133 | StaticServlet.prototype.sendForbidden_ = function(req, res, path) { 134 | path = path.substring(1); 135 | res.writeHead(403, { 136 | 'Content-Type': 'text/html' 137 | }); 138 | res.write('\n'); 139 | res.write('403 Forbidden\n'); 140 | res.write('

    Forbidden

    '); 141 | res.write( 142 | '

    You do not have permission to access ' + 143 | escapeHtml(path) + ' on this server.

    ' 144 | ); 145 | res.end(); 146 | sys.puts('403 Forbidden: ' + path); 147 | }; 148 | 149 | StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) { 150 | res.writeHead(301, { 151 | 'Content-Type': 'text/html', 152 | 'Location': redirectUrl 153 | }); 154 | res.write('\n'); 155 | res.write('301 Moved Permanently\n'); 156 | res.write('

    Moved Permanently

    '); 157 | res.write( 158 | '

    The document has moved here.

    ' 161 | ); 162 | res.end(); 163 | sys.puts('301 Moved Permanently: ' + redirectUrl); 164 | }; 165 | 166 | StaticServlet.prototype.sendFile_ = function(req, res, path) { 167 | var self = this; 168 | var file = fs.createReadStream(path); 169 | res.writeHead(200, { 170 | 'Content-Type': StaticServlet. 171 | MimeMap[path.split('.').pop()] || 'text/plain' 172 | }); 173 | if (req.method === 'HEAD') { 174 | res.end(); 175 | } else { 176 | file.on('data', res.write.bind(res)); 177 | file.on('close', function() { 178 | res.end(); 179 | }); 180 | file.on('error', function(error) { 181 | self.sendError_(req, res, error); 182 | }); 183 | } 184 | }; 185 | 186 | StaticServlet.prototype.sendDirectory_ = function(req, res, path) { 187 | var self = this; 188 | if (path.match(/[^\/]$/)) { 189 | req.url.pathname += '/'; 190 | var redirectUrl = url.format(url.parse(url.format(req.url))); 191 | return self.sendRedirect_(req, res, redirectUrl); 192 | } 193 | fs.readdir(path, function(err, files) { 194 | if (err) 195 | return self.sendError_(req, res, error); 196 | 197 | if (!files.length) 198 | return self.writeDirectoryIndex_(req, res, path, []); 199 | 200 | var remaining = files.length; 201 | files.forEach(function(fileName, index) { 202 | fs.stat(path + '/' + fileName, function(err, stat) { 203 | if (err) 204 | return self.sendError_(req, res, err); 205 | if (stat.isDirectory()) { 206 | files[index] = fileName + '/'; 207 | } 208 | if (!(--remaining)) 209 | return self.writeDirectoryIndex_(req, res, path, files); 210 | }); 211 | }); 212 | }); 213 | }; 214 | 215 | StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) { 216 | path = path.substring(1); 217 | res.writeHead(200, { 218 | 'Content-Type': 'text/html' 219 | }); 220 | if (req.method === 'HEAD') { 221 | res.end(); 222 | return; 223 | } 224 | res.write('\n'); 225 | res.write('' + escapeHtml(path) + '\n'); 226 | res.write('\n'); 229 | res.write('

    Directory: ' + escapeHtml(path) + '

    '); 230 | res.write('
      '); 231 | files.forEach(function(fileName) { 232 | if (fileName.charAt(0) !== '.') { 233 | res.write('
    1. ' + 235 | escapeHtml(fileName) + '
    2. '); 236 | } 237 | }); 238 | res.write('
    '); 239 | res.end(); 240 | }; 241 | 242 | // Must be last, 243 | main(process.argv); 244 | -------------------------------------------------------------------------------- /TryRequireJs/myPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My Sample Project 5 | 7 | 8 | 9 | 10 | 11 |

    My Sample Project

    12 |

    hello

    13 | 14 | 15 | -------------------------------------------------------------------------------- /TryRequireJs/scripts/main.js: -------------------------------------------------------------------------------- 1 | //main.js是入口点 2 | require(["subDir1/util1"], function(util1) { 3 | alert("util1 loaded!"); 4 | }); 5 | -------------------------------------------------------------------------------- /TryRequireJs/scripts/subDir1/util1.js: -------------------------------------------------------------------------------- 1 | alert("i am util1"); 2 | 3 | //main加载util1,然后util1加载util2,util2是一个module 4 | //util2返回一个JSON对象,该对象包含下面调到的两个function 5 | require(["subDir2/util2"], function(util2) { 6 | util2.alertUtil("using a function from util2, util2 is a module now, its functions are not global"); 7 | util2.changeP(); 8 | }); -------------------------------------------------------------------------------- /TryRequireJs/scripts/subDir2/util2.js: -------------------------------------------------------------------------------- 1 | //util2 define一个module,返回一个包含两个function的json 2 | define(function(){ 3 | function util2AlertHelper(param){ 4 | alert(param); 5 | } 6 | function changePElement(){ 7 | var p = document.getElementById("container"); 8 | p.innerText = "i am util2"; 9 | } 10 | return {alertUtil:util2AlertHelper, changeP:changePElement}; 11 | }) -------------------------------------------------------------------------------- /TryRequireJs/stick_price_tmp.js: -------------------------------------------------------------------------------- 1 | var priceArray = [ 2 | {length:1, averagePrice:3 / 1}, 3 | {length:2, averagePrice:2 / 2}, 4 | {length:3, averagePrice:5 / 3}, 5 | {length:4, averagePrice:4 / 4} 6 | ]; 7 | 8 | var sortedPriceArray = priceArray.sort(function (item1, item2) { 9 | return item2.averagePrice - item1.averagePrice; 10 | }); 11 | 12 | var index = 0; 13 | var stickLength = 4; 14 | var max = sortedPriceArray[0]; 15 | var totalPrice = 0; 16 | 17 | function calculate() { 18 | while (stickLength >= max.length) { 19 | stickLength = stickLength - max.length; 20 | totalPrice = totalPrice + max.length * max.averagePrice; 21 | } 22 | 23 | if (index != sortedPriceArray.length && stickLength > 0) { 24 | index = index + 1; 25 | max = sortedPriceArray[index]; 26 | calculate(); 27 | } 28 | }; 29 | 30 | calculate(); 31 | 32 | console.log(totalPrice); -------------------------------------------------------------------------------- /dropdowndemo/dropdowndemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bootstrap, from Twitter 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dropdowndemo/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /* =================================================== 2 | * bootstrap-transition.js v2.2.2 3 | * http://twitter.github.com/bootstrap/javascript.html#transitions 4 | * =================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 27 | * ======================================================= */ 28 | 29 | $(function () { 30 | 31 | $.support.transition = (function () { 32 | 33 | var transitionEnd = (function () { 34 | 35 | var el = document.createElement('bootstrap') 36 | , transEndEventNames = { 37 | 'WebkitTransition' : 'webkitTransitionEnd' 38 | , 'MozTransition' : 'transitionend' 39 | , 'OTransition' : 'oTransitionEnd otransitionend' 40 | , 'transition' : 'transitionend' 41 | } 42 | , name 43 | 44 | for (name in transEndEventNames){ 45 | if (el.style[name] !== undefined) { 46 | return transEndEventNames[name] 47 | } 48 | } 49 | 50 | }()) 51 | 52 | return transitionEnd && { 53 | end: transitionEnd 54 | } 55 | 56 | })() 57 | 58 | }) 59 | 60 | }(window.jQuery); 61 | /* ========================================================= 62 | * bootstrap-modal.js v2.2.2 63 | * http://twitter.github.com/bootstrap/javascript.html#modals 64 | * ========================================================= 65 | * Copyright 2012 Twitter, Inc. 66 | * 67 | * Licensed under the Apache License, Version 2.0 (the "License"); 68 | * you may not use this file except in compliance with the License. 69 | * You may obtain a copy of the License at 70 | * 71 | * http://www.apache.org/licenses/LICENSE-2.0 72 | * 73 | * Unless required by applicable law or agreed to in writing, software 74 | * distributed under the License is distributed on an "AS IS" BASIS, 75 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 76 | * See the License for the specific language governing permissions and 77 | * limitations under the License. 78 | * ========================================================= */ 79 | 80 | 81 | !function ($) { 82 | 83 | "use strict"; // jshint ;_; 84 | 85 | 86 | /* MODAL CLASS DEFINITION 87 | * ====================== */ 88 | 89 | var Modal = function (element, options) { 90 | this.options = options 91 | this.$element = $(element) 92 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) 93 | this.options.remote && this.$element.find('.modal-body').load(this.options.remote) 94 | } 95 | 96 | Modal.prototype = { 97 | 98 | constructor: Modal 99 | 100 | , toggle: function () { 101 | return this[!this.isShown ? 'show' : 'hide']() 102 | } 103 | 104 | , show: function () { 105 | var that = this 106 | , e = $.Event('show') 107 | 108 | this.$element.trigger(e) 109 | 110 | if (this.isShown || e.isDefaultPrevented()) return 111 | 112 | this.isShown = true 113 | 114 | this.escape() 115 | 116 | this.backdrop(function () { 117 | var transition = $.support.transition && that.$element.hasClass('fade') 118 | 119 | if (!that.$element.parent().length) { 120 | that.$element.appendTo(document.body) //don't move modals dom position 121 | } 122 | 123 | that.$element 124 | .show() 125 | 126 | if (transition) { 127 | that.$element[0].offsetWidth // force reflow 128 | } 129 | 130 | that.$element 131 | .addClass('in') 132 | .attr('aria-hidden', false) 133 | 134 | that.enforceFocus() 135 | 136 | transition ? 137 | that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) : 138 | that.$element.focus().trigger('shown') 139 | 140 | }) 141 | } 142 | 143 | , hide: function (e) { 144 | e && e.preventDefault() 145 | 146 | var that = this 147 | 148 | e = $.Event('hide') 149 | 150 | this.$element.trigger(e) 151 | 152 | if (!this.isShown || e.isDefaultPrevented()) return 153 | 154 | this.isShown = false 155 | 156 | this.escape() 157 | 158 | $(document).off('focusin.modal') 159 | 160 | this.$element 161 | .removeClass('in') 162 | .attr('aria-hidden', true) 163 | 164 | $.support.transition && this.$element.hasClass('fade') ? 165 | this.hideWithTransition() : 166 | this.hideModal() 167 | } 168 | 169 | , enforceFocus: function () { 170 | var that = this 171 | $(document).on('focusin.modal', function (e) { 172 | if (that.$element[0] !== e.target && !that.$element.has(e.target).length) { 173 | that.$element.focus() 174 | } 175 | }) 176 | } 177 | 178 | , escape: function () { 179 | var that = this 180 | if (this.isShown && this.options.keyboard) { 181 | this.$element.on('keyup.dismiss.modal', function ( e ) { 182 | e.which == 27 && that.hide() 183 | }) 184 | } else if (!this.isShown) { 185 | this.$element.off('keyup.dismiss.modal') 186 | } 187 | } 188 | 189 | , hideWithTransition: function () { 190 | var that = this 191 | , timeout = setTimeout(function () { 192 | that.$element.off($.support.transition.end) 193 | that.hideModal() 194 | }, 500) 195 | 196 | this.$element.one($.support.transition.end, function () { 197 | clearTimeout(timeout) 198 | that.hideModal() 199 | }) 200 | } 201 | 202 | , hideModal: function (that) { 203 | this.$element 204 | .hide() 205 | .trigger('hidden') 206 | 207 | this.backdrop() 208 | } 209 | 210 | , removeBackdrop: function () { 211 | this.$backdrop.remove() 212 | this.$backdrop = null 213 | } 214 | 215 | , backdrop: function (callback) { 216 | var that = this 217 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 218 | 219 | if (this.isShown && this.options.backdrop) { 220 | var doAnimate = $.support.transition && animate 221 | 222 | this.$backdrop = $('