mockup/master: Closes #772, search for files and text within files.
Oshane Bailey <jenkins-z4DKO/[email protected]>
| Newsgroups | gmane.comp.web.zope.plone.cvs |
|---|---|
| Message-ID | <[email protected]> |
Repository: mockup Branch: refs/heads/master Date: 2017-06-27T18:40:08-05:00 Author: Oshane Bailey (b4oshany) <[email protected]> Commit: https://github.com/plone/mockup/commit/851b85caf702f72d64aa67907d251a9babe51518 Closes #772, search for files and text within files. Files changed: A mockup/js/ui/templates/dropdown.xml A mockup/js/ui/views/anchor.js A mockup/js/ui/views/dropdown.js A mockup/patterns/filemanager/js/findfile.js A mockup/patterns/filemanager/js/findinfiles.js A mockup/patterns/filemanager/templates/popover.xml M CHANGES.rst M mockup/patterns/filemanager/js/basepopover.js M mockup/patterns/filemanager/pattern.filemanager.less M mockup/patterns/filemanager/pattern.js M mockup/patterns/filemanager/templates/app.xml M mockup/patterns/relateditems/pattern.js D mockup/patterns/filemanager/js/filesearch.js diff --git a/CHANGES.rst b/CHANGES.rst index e57d16a7..254e796a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,6 +12,14 @@ New features: - Make thumb scale in folder contents listing adjustable/supressable. Replace meaningless paper clip icon (fontello) with mime type icons from mimetype registry. + - Search for files and opening the file upon click + - Search for text within files and opening the file upon click + - Added Bootstrap Dropdown menu to the UI views + - Added Anchor (a) tag to the UI views + + - make thumb size in folder contents listing adjustable/supressable + replace meaningless paper clip icon (fontello) with mime type icons + from mimetype registry https://github.com/plone/Products.CMFPlone/issues/1734 [fgrcon] diff --git a/mockup/js/ui/templates/dropdown.xml b/mockup/js/ui/templates/dropdown.xml new file mode 100644 index 00000000..ffb2492a --- /dev/null +++ b/mockup/js/ui/templates/dropdown.xml @@ -0,0 +1,9 @@ + +<a style="padding-top: 8px" href="#" class="btn btn-default dropdown-toggle" type="button" id="dropdown-menu-" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + <span class="dropdown-title"> + + </span> + <span class="caret"></span> +</a> +<ul class="dropdown-menu items dropdown-content" aria-labelledby="dropdown-menu-"> +</ul> diff --git a/mockup/js/ui/views/anchor.js b/mockup/js/ui/views/anchor.js new file mode 100644 index 00000000..df83e45e --- /dev/null +++ b/mockup/js/ui/views/anchor.js @@ -0,0 +1,56 @@ +define([ + 'underscore', + 'mockup-ui-url/views/base', + 'mockup-patterns-tooltip' +], function(_, BaseView, Tooltip) { + 'use strict'; + + var AnchorView = BaseView.extend({ + tagName: 'a', + className: 'alink', + eventPrefix: 'button', + context: 'default', + idPrefix: 'alink-', + attributes: { + 'href': '#' + }, + extraClasses: [], + tooltip: null, + template: '<% if (icon) { %><span class="glyphicon glyphicon-<%= icon %>"></span><% } %> <%= title %>', + events: { + 'click': 'handleClick' + }, + initialize: function(options) { + if (!options.id) { + var title = options.title || ''; + options.id = title !== '' ? title.toLowerCase().replace(' ', '-') : this.cid; + } + BaseView.prototype.initialize.apply(this, [options]); + + this.on('render', function() { + this.$el.attr('title', this.options.title || ''); + this.$el.attr('aria-label', this.options.title || this.options.tooltip || ''); + _.each(this.extraClasses, function(klass){ + this.$el.addClass(klass); + }); + }, this); + }, + handleClick: function(e) { + e.preventDefault(); + if (!this.$el.prop('disabled')) { + this.uiEventTrigger('click', this, e); + } + }, + serializedModel: function() { + return _.extend({'icon': '', 'title': ''}, this.options); + }, + disable: function() { + this.$el.prop('disabled', true); + }, + enable: function() { + this.$el.prop('disabled', false); + } + }); + + return AnchorView; +}); diff --git a/mockup/js/ui/views/dropdown.js b/mockup/js/ui/views/dropdown.js new file mode 100644 index 00000000..6e4505a0 --- /dev/null +++ b/mockup/js/ui/views/dropdown.js @@ -0,0 +1,56 @@ +define([ + 'underscore', + 'mockup-ui-url/views/buttongroup', + 'text!mockup-ui-url/templates/dropdown.xml', +], function(_, ButtonGroup, DropdownTemplate) { + 'use strict'; + + var DropdownView = ButtonGroup.extend({ + idPrefix: 'btngroup-dropdown-', + template: DropdownTemplate, + itemContainer: "ul.dropdown-content", + title: null, + + initialize: function(options) { + ButtonGroup.prototype.initialize.apply(this, [options]); + + this.on('render', function() { + this.renderTitle(); + }, this); + }, + + renderTitle: function() { + var title = this.options.title; + if(this.options.title == undefined){ + title = this.title; + if(this.title == null){ + title = "Menu Option"; + } + } + this.$('.dropdown-title').empty().append(title); + }, + + renderItems: function() { + var $container; + + if (this.itemContainer !== null) { + $container = $(this.itemContainer, this.$el); + if ($container.length === 0) { + throw 'Item Container element not found.'; + } + } else { + $container = this.$el; + } + + var $item = null; + _.each(this.items, function(view) { + $item = $("<li></li>"); + $item.append(view.render().$el.removeClass("btn")); + $container.append($item); + }, this); + }, + + }); + + return DropdownView; +}); diff --git a/mockup/patterns/filemanager/js/basepopover.js b/mockup/patterns/filemanager/js/basepopover.js index fee2ab53..61796918 100644 --- a/mockup/patterns/filemanager/js/basepopover.js +++ b/mockup/patterns/filemanager/js/basepopover.js @@ -1,22 +1,52 @@ define([ 'underscore', - 'mockup-ui-url/views/popover' -], function(_, PopoverView) { + 'mockup-ui-url/views/popover', + 'text!mockup-patterns-filemanager-url/templates/popover.xml', +], function(_, PopoverView, PopoverTemplate) { 'use strict'; var FileManagerPopover = PopoverView.extend({ className: 'popover', title: _.template('nothing'), content: _.template('<div/>'), + template: PopoverTemplate, initialize: function(options) { this.app = options.app; PopoverView.prototype.initialize.apply(this, [options]); }, + afterRender: function () { + var self = this; + self.$el.find(".popover-close").click(function(e){ + self.hide(true); + }); + return self; + }, + getBodyClassName: function(){ + var name = 'popover-'; + if(this.options.id){ + name += this.options.id + '-'; + } + name += 'active'; + return name; + }, render: function() { var self = this; PopoverView.prototype.render.call(this); return self; }, + hide: function(closePopover) { + if(this.closeOnOutClick || closePopover == true){ + this.opened = false; + this.$el.removeClass('active'); + if (this.triggerView) { + this.triggerView.$el.removeClass('active'); + this.triggerView.$el.attr('aria-hidden', 'true'); + } + this.uiEventTrigger('hide', this); + this.$el.attr('aria-hidden', 'true'); + $('body').removeClass(this.getBodyClassName()); + } + }, toggle: function(button, e) { PopoverView.prototype.toggle.apply(this, [button, e]); var self = this; diff --git a/mockup/patterns/filemanager/js/filesearch.js b/mockup/patterns/filemanager/js/filesearch.js deleted file mode 100644 index be5c35d1..00000000 --- a/mockup/patterns/filemanager/js/filesearch.js +++ /dev/null @@ -1,73 +0,0 @@ -define([ - 'jquery', - 'underscore', - 'mockup-patterns-filemanager-url/js/basepopover', - 'translate' -], function($, _, PopoverView, _t) { - 'use strict'; - - var FileSearchView = PopoverView.extend({ - className: 'popover filesearch', - title: _.template('<%= _t("File Search") %>'), - content: _.template( - '<form>' + - '<div class="input-group">' + - '<input type="text" class="search form-control" ' + - 'id="file-search-field" placeholder="<%= _t("Find theme resource in plone") %>">' + - '<span class="input-group-btn">' + - '<input type="submit" class="btn btn-primary" value="<%= _t("Search") %>"/>' + - '</span>' + - '</div>' + - '</form>' + - '<ul class="results list-group">' + - '</ul>' - ), - render: function() { - var self = this; - PopoverView.prototype.render.call(this); - self.$form = self.$('form'); - self.$results = self.$('.results'); - self.$form.submit(function(e) { - e.preventDefault(); - $.ajax({ - url: self.app.options.resourceSearchUrl, - dataType: 'json', - success: function(data) { - self.$results.empty(); - _.each(data, function(item) { - var $item = $( - '<li class="list-group-item" data-id="' + item.id + '">' + - '<span class="badge"><a href=#">' + _t('Customize') + '</a></span>' + - item.id + - '</li>'); - $('a', $item).click(function(e) { - e.preventDefault(); - self.customize($(this).parents('li').eq(0).attr('data-id')); - }); - self.$results.append($item); - }); - } - }); - }); - return self; - }, - customize: function(resource) { - var self = this; - self.app.doAction('customize', { - type: 'POST', - data: { - resource: resource - }, - success: function(data) { - self.hide(); - // clear out - self.$('input.search').attr('value', ''); - self.$results.empty(); - self.app.refreshTree(); - } - }); - } - }); - - return FileSearchView; -}); diff --git a/mockup/patterns/filemanager/js/findfile.js b/mockup/patterns/filemanager/js/findfile.js new file mode 100644 index 00000000..d4c0c3dd --- /dev/null +++ b/mockup/patterns/filemanager/js/findfile.js @@ -0,0 +1,101 @@ +define([ + 'jquery', + 'underscore', + 'mockup-patterns-filemanager-url/js/basepopover', + 'translate' +], function($, _, PopoverView, _t) { + 'use strict'; + + var FindFile = PopoverView.extend({ + className: 'popover filesearch', + closeOnOutClick: false, + backdropOptions: { + zIndex: '1009', + opacity: '0.4', + className: 'backdrop backdrop-popover', + classActiveName: 'backdrop-active', + closeOnEsc: false, + closeOnClick: false + }, + title: _.template('<%= _t("Find File") %>'), + content: _.template( + '<form>' + + '<div class="input-group">' + + '<input type="text" class="search form-control" ' + + 'id="file-search-field" placeholder="<%= _t("Find theme resource in plone") %>">' + + '</div>' + + '<div class="input-group">' + + '<input type="submit" class="btn btn-primary" value="<%= _t("Search") %>"/>' + + '</div>' + + '</form><br/>' + + '<ul class="results list-group">' + + '</ul>' + ), + appendToResults: function(item){ + var self = this; + var $item = $( + '<li class="list-group-item">' + + '<span class="badge"><a data-target="' + item.path + '" href=#">' + + _t(item.filename) + '</a></span>' + + '</li>'); + $('a', $item).click(function(e) { + e.preventDefault(); + self.findfile($(this).attr('data-target')); + }); + self.$results.append($item); + }, + filterFiles: function(patt, data){ + var self = this; + _.each(data, function(item) { + if(item.folder){ + self.filterFiles(patt, item.children); + }else{ + if(patt.test(item.filename)){ + self.appendToResults(item); + self.noMatches++; + } + } + }); + }, + render: function() { + var self = this; + PopoverView.prototype.render.call(this); + self.$form = self.$('form'); + self.$searchFor = self.$("input"); + self.$results = self.$('.results'); + self.$form.submit(function(e) { + e.preventDefault(); + $.ajax({ + url: self.app.options.actionUrl + '?action=dataTree', + dataType: 'json', + success: function(data) { + self.$results.empty(); + self.noMatches = 0; + var searchFor = self.$searchFor.val(); + var patt = new RegExp(searchFor, "g"); + self.filterFiles(patt, data); + if(self.noMatches == 0){ + self.$results.append("<span>No results found for " + searchFor + "</span>"); + } + } + }); + }); + return self; + }, + findfile: function(resource) { + var self = this; + self.app.doAction('getFile', { + data: { + path: resource + }, + dataType: 'json', + success: function(data) { + self.app.fileData[resource] = data; + self.app.openEditor(resource); + } + }); + } + }); + + return FindFile; +}); diff --git a/mockup/patterns/filemanager/js/findinfiles.js b/mockup/patterns/filemanager/js/findinfiles.js new file mode 100644 index 00000000..904741f9 --- /dev/null +++ b/mockup/patterns/filemanager/js/findinfiles.js @@ -0,0 +1,134 @@ +define([ + 'jquery', + 'underscore', + 'mockup-patterns-filemanager-url/js/basepopover', + 'translate' +], function($, _, PopoverView, _t) { + 'use strict'; + + var FindInFiles = PopoverView.extend({ + className: 'popover filesearch', + closeOnOutClick: false, + backdropOptions: { + zIndex: '1009', + opacity: '0.4', + className: 'backdrop backdrop-popover', + classActiveName: 'backdrop-active', + closeOnEsc: false, + closeOnClick: false + }, + title: _.template('<%= _t("File in File") %>'), + content: _.template( + '<form>' + + '<div class="input-group">' + + '<input type="text" class="search form-control" ' + + 'id="file-search-field" placeholder="<%= _t("Find text witin theme resource in plone") %>">' + + '</div>' + + '<div class="input-group">' + + '<input type="submit" class="btn btn-primary" value="<%= _t("Search") %>"/>' + + '</div>' + + '</form><br/>' + + '<ul style="max-height: 400px; overflow: auto;" class="results list-group">' + + '</ul>' + ), + appendToResults: function(item){ + var self = this, seen = null; + var file_item = + '<li class="list-group-item" data-id="' + item.file.label + '">' + + '<span class="badge">' + _t(item.file.filename) + '</span><ul>'; + for(var x in item.lines){ + seen = item.lines[x]; + file_item += '<li class="list-group-item" data-id="' + item.file.label + '">' + + '<span class="badge"><a class="ff-open-file" data-target="'+item.file.path+'" ' + + 'target-line="'+seen.line+'" href="#">Line ' + + '<span style="display: inline-block; width: 100px;">' + seen.line + + '</span><span>'+seen.text+'</span><a></span></li>'; + } + file_item += '</ul></li>'; + var $item = $(file_item); + $('a', $item).click(function(e) { + e.preventDefault(); + self.findinfiles($(this).attr("data-target")); + }); + self.$results.append($item); + }, + + filterFile: function(patt, item){ + var self = this; + $.ajax({ + url: self.app.options.actionUrl + '?action=getFile&path='+item.path.replace("/", "%2F"), + dataType: 'json', + success: function(data) { + var contents = data["contents"]; + if(contents == undefined){ + return; + } + var lines = contents.split("\n"); + var seen = [], line = ''; + var result = null; + for(var x in lines){ + line = lines[x]; + result = patt.exec(line); + if(result != null){ + seen.push({ + "line": parseInt(x) + 1, + "text": '<b>'+result[0]+'</b>'+line.substr(result["index"] + result[0].length, 20) + }); + } + } + if(seen.length > 0){ + self.appendToResults({file: item, lines: seen}); + self.noMatches += seen.length; + } + } + }); + }, + filterFiles: function(patt, data){ + var self = this; + _.each(data, function(item) { + if(item.folder){ + self.filterFiles(patt, item.children); + }else{ + self.filterFile(patt, item); + } + }); + }, + render: function() { + var self = this; + PopoverView.prototype.render.call(this); + self.$form = self.$('form'); + self.$searchFor = self.$("input"); + self.$results = self.$('.results'); + self.$form.submit(function(e) { + e.preventDefault(); + $.ajax({ + url: self.app.options.actionUrl + '?action=dataTree', + dataType: 'json', + success: function(data) { + self.$results.empty(); + self.noMatches = 0; + var searchFor = self.$searchFor.val(); + var patt = new RegExp(searchFor, "g"); + self.filterFiles(patt, data); + } + }); + }); + return self; + }, + findinfiles: function(resource) { + var self = this; + self.app.doAction('getFile', { + data: { + path: resource + }, + dataType: 'json', + success: function(data) { + self.app.fileData[resource] = data; + self.app.openEditor(resource); + } + }); + } + }); + + return FindInFiles; +}); diff --git a/mockup/patterns/filemanager/pattern.filemanager.less b/mockup/patterns/filemanager/pattern.filemanager.less index b5fd4216..c37f28ac 100644 --- a/mockup/patterns/filemanager/pattern.filemanager.less +++ b/mockup/patterns/filemanager/pattern.filemanager.less @@ -27,6 +27,11 @@ .popover:extend(.popover all){} .popover-title:extend(.popover-title all){} .popover-content:extend(.popover-content all){} + + .popover{ + max-width: 600px; + } + .arrow:extend(.arrow all){} .table:extend(.table all){} diff --git a/mockup/patterns/filemanager/pattern.js b/mockup/patterns/filemanager/pattern.js index 5ab7b96a..916780f3 100644 --- a/mockup/patterns/filemanager/pattern.js +++ b/mockup/patterns/filemanager/pattern.js @@ -40,19 +40,23 @@ define([ 'mockup-ui-url/views/toolbar', 'mockup-ui-url/views/button', 'mockup-ui-url/views/buttongroup', + 'mockup-ui-url/views/anchor', + 'mockup-ui-url/views/dropdown', 'mockup-patterns-filemanager-url/js/addnew', 'mockup-patterns-filemanager-url/js/newfolder', - 'mockup-patterns-filemanager-url/js/filesearch', + 'mockup-patterns-filemanager-url/js/findfile', + 'mockup-patterns-filemanager-url/js/findinfiles', 'mockup-patterns-filemanager-url/js/delete', 'mockup-patterns-filemanager-url/js/customize', 'mockup-patterns-filemanager-url/js/rename', 'mockup-patterns-filemanager-url/js/upload', 'translate', 'mockup-utils', - 'text!mockup-ui-url/templates/popover.xml' + 'text!mockup-ui-url/templates/popover.xml', + 'text!mockup-ui-url/templates/dropdown.xml' ], function($, Base, _, Tree, TextEditor, AppTemplate, Toolbar, - ButtonView, ButtonGroup, AddNewView, NewFolderView, DeleteView, - FileSearchView, + ButtonView, ButtonGroup, AnchorView, DropdownView, + AddNewView, NewFolderView, FindFileView, FindInFilesView, DeleteView, CustomizeView, RenameView, UploadView, _t, utils) { 'use strict'; @@ -137,16 +141,26 @@ define([ }), app: self }); - var fileSearchView = new FileSearchView({ - triggerView: new ButtonView({ - id: 'filesarch', - title: _t('File Search'), + var findFileView = new FindFileView({ + triggerView: new AnchorView({ + id: 'findfile', + title: _t('Find File'), tooltip: _t('Find theme resource in plone'), icon: 'file', context: 'default' }), app: self }); + var findinFilesView = new FindInFilesView({ + triggerView: new AnchorView({ + id: 'findinfiles', + title: _t('Find in Files'), + tooltip: _t('Find text within theme resource in plone'), + icon: 'file', + context: 'default' + }), + app: self + }); var renameView = new RenameView({ triggerView: new ButtonView({ id: 'rename', @@ -168,18 +182,29 @@ define([ app: self }); + var find_menu = new DropdownView({ + title: _t('Find'), + items: [ + findFileView.triggerView, + findinFilesView.triggerView + ], + id: 'find', + app: self + }) + self.views = [ newFolderView, addNewView, - fileSearchView, + findFileView, + findinFilesView, renameView, deleteView ]; var mainButtons = [ self.saveBtn, newFolderView.triggerView, - fileSearchView.triggerView, addNewView.triggerView, + find_menu, renameView.triggerView, deleteView.triggerView ]; @@ -304,6 +329,7 @@ define([ } }); + self.$tree.bind('tree.select', function(e) { if (e.node === null) { self.toggleButtons(false); diff --git a/mockup/patterns/filemanager/templates/app.xml b/mockup/patterns/filemanager/templates/app.xml index 11d594ff..e5194500 100644 --- a/mockup/patterns/filemanager/templates/app.xml +++ b/mockup/patterns/filemanager/templates/app.xml @@ -1,5 +1,7 @@ <div id="toolbar"> </div> +<div id="toolbar-action"> +</div> <div class="container"> <div class="tree"> </div> @@ -14,4 +16,4 @@ </div> </div> </nav> -</div> \ No newline at end of file +</div> diff --git a/mockup/patterns/filemanager/templates/popover.xml b/mockup/patterns/filemanager/templates/popover.xml new file mode 100644 index 00000000..a276f070 --- /dev/null +++ b/mockup/patterns/filemanager/templates/popover.xml @@ -0,0 +1,12 @@ +<div class="arrow"></div> +<div class="popover-label"> +<div style="position: relative;" class="popover-title"> +</div> +<a style="position: absolute; top: 5px; right: 3px; font-size: 16px; color: #999;" + href="#" class="popover-close"> + <span class="glyphicon glyphicon-remove"></span> +</a> +</div> +<div class="items popover-content"> +</div> + diff --git a/mockup/patterns/relateditems/pattern.js b/mockup/patterns/relateditems/pattern.js index f10d3145..00ff3883 100644 --- a/mockup/patterns/relateditems/pattern.js +++ b/mockup/patterns/relateditems/pattern.js @@ -98,11 +98,11 @@ define([ 'mockup-utils', 'pat-registry', 'translate', - 'text!mockup-patterns-relateditems-url/templates/breadcrumb.xml', - 'text!mockup-patterns-relateditems-url/templates/favorite.xml', - 'text!mockup-patterns-relateditems-url/templates/result.xml', - 'text!mockup-patterns-relateditems-url/templates/selection.xml', - 'text!mockup-patterns-relateditems-url/templates/toolbar.xml', +// 'text!mockup-patterns-relateditems-url/templates/breadcrumb.xml', +// 'text!mockup-patterns-relateditems-url/templates/favorite.xml', +// 'text!mockup-patterns-relateditems-url/templates/result.xml', +// 'text!mockup-patterns-relateditems-url/templates/selection.xml', +// 'text!mockup-patterns-relateditems-url/templates/toolbar.xml', 'bootstrap-dropdown' ], function($, _, Base, Select2, ButtonView, utils, registry, _t, BreadcrumbTemplate, ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot