diff --git a/editor/js/main.js b/editor/js/main.js index 06fd8cf9f..363db9b87 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -56,7 +56,7 @@ var RED = (function() { success: function(data) { $("body").append(data); $("body").i18n(); - $(".palette-spinner").hide(); + $("#palette > .palette-spinner").hide(); $(".palette-scroll").removeClass("hide"); $("#palette-search").removeClass("hide"); loadFlows(); diff --git a/editor/js/ui/palette-editor.js b/editor/js/ui/palette-editor.js index f2fc57a02..4825d2f28 100644 --- a/editor/js/ui/palette-editor.js +++ b/editor/js/ui/palette-editor.js @@ -15,11 +15,17 @@ **/ RED.palette.editor = (function() { + var editorTabs; + var filterInput; + var searchInput; var nodeList; + var packageList; + var loadedList = []; + var filteredList = []; + var typesInUse = {}; var nodeEntries = {}; var eventTimers = {}; - var activeFilter = ""; function delayCallback(start,callback) { @@ -55,6 +61,23 @@ RED.palette.editor = (function() { }); }) } + function installNodeModule(id,shade,callback) { + shade.show(); + $.ajax({ + url:"nodes", + type: "POST", + data: JSON.stringify({ + module: id + }), + contentType: "application/json; charset=utf-8" + }).done(function(data,textStatus,xhr) { + shade.hide(); + callback(); + }).fail(function(xhr,textStatus,err) { + shade.hide(); + callback(xhr); + }); + } function removeNodeModule(id,callback) { $.ajax({ url:"nodes/"+id, @@ -92,6 +115,70 @@ RED.palette.editor = (function() { return rgbColor; } + function formatUpdatedAt(dateString) { + var now = new Date(); + var d = new Date(dateString); + var delta = now.getTime() - d.getTime(); + + delta /= 1000; + + if (delta < 60) { + return "seconds ago"; + } + + delta = Math.floor(delta/60); + + if (delta < 10) { + return "minutes ago"; + } + if (delta < 60) { + return delta+" minutes ago"; + } + + delta = Math.floor(delta/60); + + if (delta < 24) { + return delta+" hour"+(delta>1?"s":"")+" ago"; + } + + delta = Math.floor(delta/24); + + if (delta < 7) { + return delta+" day"+(delta>1?"s":"")+" ago"; + } + var weeks = Math.floor(delta/7); + var days = delta%7; + + if (weeks < 4) { + if (days === 0) { + return weeks+" week"+(weeks>1?"s":"")+" ago"; + } else { + return weeks+" week"+(weeks>1?"s":"")+", "+days+" day"+(days>1?"s":"")+" ago"; + } + } + + var months = Math.floor(weeks/4); + weeks = weeks%4; + + if (months < 12) { + if (weeks === 0) { + return months+" month"+(months>1?"s":"")+" ago"; + } else { + return months+" month"+(months>1?"s":"")+", "+weeks+" week"+(weeks>1?"s":"")+" ago"; + } + } + + var years = Math.floor(months/12); + months = months%12; + + if (months === 0) { + return years+" year"+(years>1?"s":"")+" ago"; + } else { + return years+" year"+(years>1?"s":"")+", "+months+" month"+(months>1?"s":"")+" ago"; + } + + } + function _refreshNodeModule(module) { if (!nodeEntries.hasOwnProperty(module)) { @@ -187,6 +274,10 @@ RED.palette.editor = (function() { $("#editor-shade").show(); $("#sidebar-shade").show(); $("#main-container").addClass("palette-expanded"); + setTimeout(function() { + editorTabs.resize(); + },250); + } function hidePaletteEditor() { $("#main-container").removeClass("palette-expanded"); @@ -197,22 +288,59 @@ RED.palette.editor = (function() { $(el).find(".palette-module-content").slideUp(); $(el).removeClass('expanded'); }); - $("#palette-editor-search input").val(""); - filterChange(""); + filterInput.searchBox('value',""); } function filterChange(val) { + activeFilter = val.toLowerCase(); + var visible = nodeList.editableList('filter'); + var size = nodeList.editableList('length'); if (val === "") { - $("#palette-editor-search a").hide(); - activeFilter = val; + filterInput.searchBox('count'); } else { - $("#palette-editor-search a").show(); - activeFilter = val.toLowerCase(); + filterInput.searchBox('count',visible+" / "+size); } - nodeList.editableList('filter'); } + function initInstallTab() { + $("#palette-module-install-shade").show(); + $.getJSON('http://catalog.nodered.org/catalog.json',function(v) { + loadedList = v; + searchInput.searchBox('count',loadedList.length); + loadedList.forEach(function(m) { + m.index = [m.id]; + if (m.keywords) { + m.index = m.index.concat(m.keywords); + } + m.index = m.index.join(",").toLowerCase(); + }) + $("#palette-module-install-shade").hide(); + + }) + + } function init() { + + editorTabs = RED.tabs.create({ + id:"palette-editor-tabs", + onchange:function(tab) { + $("#palette-editor .palette-editor-tab").hide(); + tab.content.show(); + if (tab.id === 'install') { + initInstallTab(); + if (searchInput) { + searchInput.focus(); + } + } else { + if (filterInput) { + filterInput.focus(); + } + } + }, + minimumActiveTabWidth: 110 + }); + + $("#editor-shade").click(function() { if ($("#main-container").hasClass("palette-expanded")) { hidePaletteEditor(); @@ -229,30 +357,27 @@ RED.palette.editor = (function() { hidePaletteEditor(); }) - var divTabs = $('
',{style:"position:absolute;top:80px;left:0;right:0;bottom:0"}).appendTo("#palette-editor"); + var modulesTab = $('
',{class:"palette-editor-tab"}).appendTo("#palette-editor"); - var searchDiv = $('
',{id:"palette-editor-search",class:"palette-search"}).appendTo(divTabs); - $('').appendTo(searchDiv) + editorTabs.addTab({ + id: 'nodes', + label: 'Nodes', + name: 'Nodes', + content: modulesTab + }) - $("#palette-editor-search a").on("click",function(e) { - e.preventDefault(); - $("#palette-editor-search input").val(""); - filterChange(""); - $("#palette-editor-search input").focus(); - }); - - $("#palette-editor-search input").val(""); - $("#palette-editor-search input").on("keyup",function() { - filterChange($(this).val()); - }); - - $("#palette-editor-search input").on("focus",function() { - $("body").one("mousedown",function() { - $("#palette-editor-search input").blur(); + var filterDiv = $('
',{class:"palette-search"}).appendTo(modulesTab); + filterInput = $('') + .appendTo(filterDiv) + .searchBox({ + delay: 200, + change: function() { + filterChange($(this).val()); + } }); - }); - nodeList = $('
    ',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(divTabs).editableList({ + + nodeList = $('
      ',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(modulesTab).editableList({ addButton: false, sort: function(A,B) { return A.info.name.localeCompare(B.info.name); @@ -266,41 +391,29 @@ RED.palette.editor = (function() { }, addItem: function(container,i,object) { var entry = object.info; - var headerRow = $('
      ',{class:"palette-module-header"}).appendTo(container); - - var titleRow = $('
      ',{class:"palette-module-meta"}).appendTo(headerRow); - var chevron = $('').appendTo(titleRow); - var title = $('',{class:"palette-module-name"}).html(entry.name).appendTo(titleRow); - - var metaRow = $('
      ',{class:"palette-module-meta"}).appendTo(headerRow); - var version = $('').appendTo(metaRow); - $('').html(entry.version).appendTo(version); - - + var titleRow = $('
      ').appendTo(headerRow); + $('',{class:"palette-module-name"}).html(entry.name).appendTo(titleRow); + var metaRow = $('
      ').appendTo(headerRow); + $('').html(entry.version).appendTo(metaRow.find(".palette-module-version")); var buttonRow = $('
      ',{class:"palette-module-meta"}).appendTo(headerRow); - var setButton = $(' ').appendTo(buttonRow); var setCount = $('').appendTo(setButton); - var buttonGroup = $('
      ',{class:"palette-module-button-group"}).appendTo(buttonRow); var removeButton = $('').html('remove').appendTo(buttonGroup); + removeButton.click(function() { + shade.show(); + removeNodeModule(entry.name, function(xhr) { + console.log(xhr); + }) + }) if (!entry.local) { removeButton.hide(); - } else { - removeButton.click(function() { - shade.show(); - removeNodeModule(entry.name, function(xhr) { - console.log(xhr); - }) - }) } var enableButton = $('').html('disable all').appendTo(buttonGroup); var contentRow = $('
      ',{class:"palette-module-content"}).appendTo(container); - var shade = $('
      ',{class:"palette-module-shade hide"}).appendTo(container); - $('').appendTo(shade); - + var shade = $('
      ').appendTo(container); object.elements = { removeButton: removeButton, @@ -365,6 +478,100 @@ RED.palette.editor = (function() { } }); + + + var installTab = $('
      ',{class:"palette-editor-tab hide"}).appendTo("#palette-editor"); + + editorTabs.addTab({ + id: 'install', + label: 'Install', + name: 'Install', + content: installTab + }) + + var searchDiv = $('
      ',{class:"palette-search"}).appendTo(installTab); + searchInput = $('') + .appendTo(searchDiv) + .searchBox({ + delay: 300, + minimumLength: 2, + change: function() { + var searchTerm = $(this).val(); + packageList.editableList('empty'); + if (searchTerm.length >= 2) { + filteredList = loadedList.filter(function(m) { + return (m.index.indexOf(searchTerm) > -1); + }).map(function(f) { return {info:f}}); + for (var i=0;i 10) { + packageList.editableList('addItem',{start:10,more:filteredList.length-10}) + } + searchInput.searchBox('count',filteredList.length+" / "+loadedList.length); + } else { + searchInput.searchBox('count',loadedList.length); + } + } + }); + + $('
      ').appendTo(installTab); + + + packageList = $('
        ',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({ + addButton: false, + // sort: function(A,B) { + // return A.info.name.localeCompare(B.info.name); + // }, + addItem: function(container,i,object) { + if (object.more) { + container.addClass('palette-module-more'); + var moreRow = $('
        ',{class:"palette-module-header palette-module"}).appendTo(container); + var moreLink = $('').html("+ "+object.more+" more").appendTo(moreRow); + moreLink.click(function(e) { + e.preventDefault(); + packageList.editableList('removeItem',object); + for (var i=object.start;i 10) { + packageList.editableList('addItem',{start:object.start+10, more:object.more-10}) + } + }) + return; + } + var entry = object.info; + var headerRow = $('
        ',{class:"palette-module-header"}).appendTo(container); + var titleRow = $('
        ').appendTo(headerRow); + $('',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow); + $('').attr('href',entry.url).appendTo(titleRow); + var descRow = $('
        ').appendTo(headerRow); + $('
        ',{class:"palette-module-description"}).html(entry.description).appendTo(descRow); + + var metaRow = $('
        ').appendTo(headerRow); + $(' '+entry.version+'').appendTo(metaRow); + $(' '+formatUpdatedAt(entry.updated_at)+'').appendTo(metaRow); + var buttonRow = $('
        ',{class:"palette-module-meta"}).appendTo(headerRow); + var buttonGroup = $('
        ',{class:"palette-module-button-group"}).appendTo(buttonRow); + var shade = $('
        ').appendTo(container); + var installButton = $('').html('install').appendTo(buttonGroup); + installButton.click(function(e) { + e.preventDefault(); + installNodeModule(entry.id,shade,function(xhr) { + console.log(xhr); + }) + }) + if (nodeEntries.hasOwnProperty(entry.id)) { + installButton.hide(); + } + + object.elements = { + installButton:installButton + } + } + }); + + RED.events.on('registry:node-set-enabled', function(ns) { refreshNodeModule(ns.module); }); @@ -381,6 +588,12 @@ RED.palette.editor = (function() { }); RED.events.on('registry:node-set-added', function(ns) { refreshNodeModule(ns.module); + for (var i=0;i .palette-spinner").show(); + + $("#palette-search input").searchBox({ + delay: 100, + change: function() { + filterChange($(this).val()); + } + }) + if (RED.settings.paletteCategories) { RED.settings.paletteCategories.forEach(function(category){ createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category})); @@ -446,24 +448,6 @@ RED.palette = (function() { }); } - $("#palette-search a").on("click",function(e) { - e.preventDefault(); - $("#palette-search input").val(""); - filterChange(""); - $("#palette-search input").focus(); - }); - - $("#palette-search input").val(""); - $("#palette-search input").on("keyup",function() { - filterChange($(this).val()); - }); - - $("#palette-search input").on("focus",function() { - $("body").one("mousedown",function() { - $("#palette-search input").blur(); - }); - }); - $("#palette-collapse-all").on("click", function(e) { e.preventDefault(); for (var cat in categoryContainers) { diff --git a/editor/sass/palette-editor.scss b/editor/sass/palette-editor.scss index 5e8330c17..a2880b7cc 100644 --- a/editor/sass/palette-editor.scss +++ b/editor/sass/palette-editor.scss @@ -27,9 +27,7 @@ background: #fff; .red-ui-editableList-container { - border-left: none; - border-right: none; - border-bottom: none; + border: none; border-radius: 0; padding: 0px; @@ -50,6 +48,14 @@ } } + .palette-editor-tab { + position:absolute; + top:115px; + left:0; + right:0; + bottom:0 + } + .palette-module-button-group { position: absolute; right: 0; @@ -68,7 +74,6 @@ text-align: center; } .palette-module-meta { - overflow: hidden; color: #666; position: relative; &.disabled { @@ -85,11 +90,25 @@ white-space: nowrap; @include enable-selection; } - .palette-module-version { + .palette-module-version, .palette-module-updated, .palette-module-link { font-style:italic; font-size: 0.8em; @include enable-selection; } + .palette-module-updated { + margin-left: 10px; + } + .palette-module-link { + margin-left: 5px; + } + + .palette-module-description { + margin-left: 20px; + font-size: 0.9em; + color: #999; + } + .palette-module-link { + } .palette-module-set-button-group { } .palette-module-count { @@ -163,5 +182,22 @@ color: #999; } } + .palette-module-more { + padding: 0 !important; + margin-top: 10px; + margin-bottom: 10px; + background: $tab-background-inactive; + a { + display: block; + text-align: center; + padding: 12px 8px; + color: #AD1625; + + &:hover { + text-decoration: none; + background: $tab-background-hover; + } + } + } } diff --git a/editor/sass/palette.scss b/editor/sass/palette.scss index 18ba0b59c..15089264c 100644 --- a/editor/sass/palette.scss +++ b/editor/sass/palette.scss @@ -69,49 +69,8 @@ padding: 3px; border-bottom: 1px solid $primary-border-color; box-sizing:border-box; - i { - font-size: 10px; - color: #666; - } - i.fa-search { - position: absolute; - pointer-events: none; - left: 12px; - top: 12px; - } - i.fa-times { - position: absolute; - right: 7px; - top: 12px; - } - input { - border-radius: 0; - border: none; - width: 100%; - box-shadow: none; - -webkit-box-shadow: none; - padding: 3px 17px 3px 22px; - margin: 0px; - height: 30px; - box-sizing:border-box; - - &:focus { - border: none; - box-shadow: none; - -webkit-box-shadow: none; - } - } - .palette-search-clear { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 20px; - display: none; - } } - #palette-footer { @include component-footer; } diff --git a/editor/templates/index.mst b/editor/templates/index.mst index bd23b55e5..2ddbea2c3 100644 --- a/editor/templates/index.mst +++ b/editor/templates/index.mst @@ -59,10 +59,11 @@
        • Manage palette
        +