Merge pull request #19 from matiasdelellis/NC15

Move to precompiled handlebars templates. and a lot of fixes..
This commit is contained in:
matiasdelellis
2019-02-12 21:12:08 -03:00
committed by GitHub
11 changed files with 228 additions and 179 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
build
js/templates.js
vendor

View File

@@ -72,6 +72,9 @@ depsmin:
wget https://github.com/varun-raj/medium-editor-autolist/raw/master/dist/autolist.min.js wget https://github.com/varun-raj/medium-editor-autolist/raw/master/dist/autolist.min.js
mv autolist.min.js vendor/autolist.js mv autolist.min.js vendor/autolist.js
js-templates:
handlebars js/templates -f js/templates.js
clean: clean:
rm -rf $(build_dir) rm -rf $(build_dir)

View File

@@ -17,6 +17,6 @@
<screenshot small-thumbnail="https://user-images.githubusercontent.com/733715/38871311-dac5a80a-4226-11e8-961d-63b276380b6b.png">https://user-images.githubusercontent.com/733715/38871311-dac5a80a-4226-11e8-961d-63b276380b6b.png</screenshot> <screenshot small-thumbnail="https://user-images.githubusercontent.com/733715/38871311-dac5a80a-4226-11e8-961d-63b276380b6b.png">https://user-images.githubusercontent.com/733715/38871311-dac5a80a-4226-11e8-961d-63b276380b6b.png</screenshot>
<screenshot>https://user-images.githubusercontent.com/733715/38871255-b07a7d5a-4226-11e8-8403-650cbea50be0.png</screenshot> <screenshot>https://user-images.githubusercontent.com/733715/38871255-b07a7d5a-4226-11e8-8403-650cbea50be0.png</screenshot>
<dependencies> <dependencies>
<nextcloud min-version="14" max-version="14" /> <nextcloud min-version="14" max-version="15"/>
</dependencies> </dependencies>
</info> </info>

View File

@@ -5,7 +5,7 @@
* later. See the COPYING file. * later. See the COPYING file.
* *
* @author Matias De lellis <mati86dl@gmail.com> * @author Matias De lellis <mati86dl@gmail.com>
* @copyright Matias De lellis 2016-2018 * @copyright Matias De lellis 2016-2019
*/ */
(function (OC, window, $, undefined) { (function (OC, window, $, undefined) {
@@ -13,15 +13,12 @@
$(document).ready(function () { $(document).ready(function () {
var translations = {
newNote: $('#new-note-string').text()
};
// this notes object holds all our notes // this notes object holds all our notes
var Notes = function (baseUrl) { var Notes = function (baseUrl) {
this._baseUrl = baseUrl; this._baseUrl = baseUrl;
this._notes = []; this._notes = [];
this._activeNote = undefined; this._activeNote = undefined;
this._loaded = false;
}; };
Notes.prototype = { Notes.prototype = {
@@ -119,12 +116,16 @@ Notes.prototype = {
$.get(this._baseUrl).done(function (notes) { $.get(this._baseUrl).done(function (notes) {
self._activeNote = undefined; self._activeNote = undefined;
self._notes = notes.reverse(); self._notes = notes.reverse();
self._loaded = true;
deferred.resolve(); deferred.resolve();
}).fail(function () { }).fail(function () {
deferred.reject(); deferred.reject();
}); });
return deferred.promise(); return deferred.promise();
}, },
isLoaded: function () {
return this._loaded;
},
updateActive: function (title, content, color) { updateActive: function (title, content, color) {
var note = this.getActive(); var note = this.getActive();
note.title = title; note.title = title;
@@ -290,10 +291,19 @@ View.prototype = {
return digits[1] + '#' + rgb.toString(16).toUpperCase(); return digits[1] + '#' + rgb.toString(16).toUpperCase();
}, },
renderContent: function () { renderContent: function () {
var source = $('#content-tpl').html(); // Remove all event handlers to prevent double events.
var template = Handlebars.compile(source); $("#app-content").off();
var html = template({notes: this._notes.getAll()});
var html = Handlebars.templates['notes']({
loaded: this._notes.isLoaded(),
notes: this._notes.getAll(),
cancelTxt: t('quicknotes', 'Cancel'),
saveTxt: t('quicknotes', 'Save'),
loadingMsg: t('quicknotes', 'Looking for your notes'),
loadingIcon: OC.imagePath('core', 'loading.gif'),
emptyMsg: t('quicknotes', 'Nothing here. Take your first quick notes'),
emptyIcon: OC.imagePath('quicknotes', 'app'),
});
$('#div-content').html(html); $('#div-content').html(html);
// Init masonty grid to notes. // Init masonty grid to notes.
@@ -323,7 +333,7 @@ View.prototype = {
// Open notes when clicking them. // Open notes when clicking them.
$("#app-content").on("click", ".quicknote", function (event) { $("#app-content").on("click", ".quicknote", function (event) {
event.stopPropagation(); // Not work so need fix on next binding.. event.stopPropagation();
if($(this).hasClass('shared')) return; //shares don't allow editing if($(this).hasClass('shared')) return; //shares don't allow editing
var modalnote = $("#modal-note-editable .quicknote"); var modalnote = $("#modal-note-editable .quicknote");
@@ -336,12 +346,8 @@ View.prototype = {
}); });
// Cancel when click outside the modal. // Cancel when click outside the modal.
$(".modal-note-background").click(function (event) { $('#app-content').on('click', '.modal-note-background', function (event) {
/* stopPropagation() not work with .on() binings. */
if (!$(event.target).is(".modal-note-background")) {
event.stopPropagation(); event.stopPropagation();
return;
}
self.cancelEdit(); self.cancelEdit();
}); });
@@ -355,12 +361,17 @@ View.prototype = {
// Remove note icon // Remove note icon
var self = this; var self = this;
$('#app-content').on("click", ".icon-delete-note", function (event) { $('#app-content').on("click", ".icon-delete-note", function (event) {
event.stopPropagation();
var note = $(this).parent().parent(); var note = $(this).parent().parent();
var id = parseInt(note.data('id'), 10); var id = parseInt(note.data('id'), 10);
event.stopPropagation();
self._notes.load(id); self._notes.load(id);
OC.dialogs.confirm(
t('quicknotes', 'Are you sure you want to delete the note?'),
t('quicknotes', 'Delete note'),
function(result) {
if (result) {
self._notes.removeActive().done(function () { self._notes.removeActive().done(function () {
if (self._notes.length() > 0) { if (self._notes.length() > 0) {
$(".notes-grid").isotope('remove', note.parent()) $(".notes-grid").isotope('remove', note.parent())
@@ -373,6 +384,10 @@ View.prototype = {
}).fail(function () { }).fail(function () {
alert('Could not delete note, not found'); alert('Could not delete note, not found');
}); });
}
},
true
);
}); });
/* /*
@@ -468,6 +483,7 @@ View.prototype = {
// handle cancel editing notes. // handle cancel editing notes.
$('#modal-note-div #cancel-button').click(function (event) { $('#modal-note-div #cancel-button').click(function (event) {
event.stopPropagation();
self.cancelEdit(); self.cancelEdit();
}); });
@@ -510,9 +526,14 @@ View.prototype = {
}); });
}, },
renderNavigation: function () { renderNavigation: function () {
var source = $('#navigation-tpl').html(); var html = Handlebars.templates['navigation']({
var template = Handlebars.compile(source); colors: this._notes.getColors(),
var html = template({colors: this._notes.getColors(), notes: this._notes.getAll()}); notes: this._notes.getAll(),
newNoteTxt: t('quicknotes', 'New note'),
allNotesTxt: t('quicknotes', 'All notes'),
colorsTxt: t('quicknotes', 'Colors'),
notesTxt: t('quicknotes', 'Notes'),
});
$('#app-navigation ul').html(html); $('#app-navigation ul').html(html);
@@ -544,26 +565,25 @@ View.prototype = {
var self = this; var self = this;
$('#new-note').click(function () { $('#new-note').click(function () {
var note = { var note = {
title: translations.newNote, title: t('quicknotes', 'New note'),
content: '', content: '',
color: '#F7EB96' color: '#F7EB96'
}; };
self._notes.create(note).done(function() { self._notes.create(note).done(function() {
if (self._notes.length() > 1) { if (self._notes.length() > 1) {
note = self._notes.getActive(); note = self._notes.getActive();
var $notehtml = $("<div class=\"note-grid-item\">" + var $notehtml = $(Handlebars.templates['note-item']({
" <div class=\"quicknote noselect\" style=\"background-color: " + note.color + "\" data-id=\"" + note.id + "\">" + color: note.color,
" <div>" + id: note.id,
" <div class=\"icon-delete hide-delete-icon icon-delete-note\" title=\"Delete\"></div>" + title: note.title,
" <div class=\"note-title\">" + note.title + "</div>" + content: note.content,
" </div>" + timestamp: note.timestamp,
" <div class=\"note-content\">" + note.content + "</div>" + }));
" </div>" +
"</div>"); $(".notes-grid").prepend($notehtml)
$(".notes-grid").prepend( $notehtml ) .isotope('prepended', $notehtml)
.isotope({ filter: '*'}) .isotope({ filter: '*'})
.isotope( 'prepended', $notehtml); .isotope('layout');
self._notes.unsetActive(); self._notes.unsetActive();
self.renderNavigation(); self.renderNavigation();
} else { } else {
@@ -579,28 +599,14 @@ View.prototype = {
$(this).toggleClass("open"); $(this).toggleClass("open");
}); });
$('#colors-folder > ul').click(function (event) {
event.stopPropagation();
});
$('#notes-folder').click(function () { $('#notes-folder').click(function () {
$(this).toggleClass("open"); $(this).toggleClass("open");
}); });
// show app menu
$('#app-navigation .app-navigation-entry-utils-menu-button').click(function () {
var entry = $(this).closest('.note');
entry.find('.app-navigation-entry-menu').toggleClass('open');
});
// delete a note
$('#app-navigation .note .delete').click(function () {
var entry = $(this).closest('.note');
entry.find('.app-navigation-entry-menu').removeClass('open');
self._notes.removeActive().done(function () {
self.render();
}).fail(function () {
alert('Could not delete note, not found');
});
});
// show a note // show a note
$('#app-navigation .note > a').click(function (event) { $('#app-navigation .note > a').click(function (event) {
event.stopPropagation(); event.stopPropagation();
@@ -639,44 +645,46 @@ View.prototype = {
} }
}; };
var timeoutID = null; function search (query) {
function filter (query) {
window.clearTimeout(timeoutID);
timeoutID = window.setTimeout(function() {
if (query) { if (query) {
query = query.toLowerCase(); query = query.toLowerCase();
$('.notes-grid').isotope({ filter: function() { $('.notes-grid').isotope({
filter: function() {
var title = $(this).find(".note-title").html().toLowerCase(); var title = $(this).find(".note-title").html().toLowerCase();
if (title.search(query) >= 0) if (title.search(query) >= 0)
return true; return true;
var content = $(this).find(".note-content").html().toLowerCase(); var content = $(this).find(".note-content").html().toLowerCase();
if (content.search(query) >= 0) if (content.search(query) >= 0)
return true; return true;
return false; return false;
}}); }
});
} else { } else {
$('.notes-grid').isotope({ filter: '*'}); $('.notes-grid').isotope({ filter: '*'});
} }
}, 500);
}; };
var SearchProxy = { new OCA.Search(search, function() {
attach: function(search) { search('');
search.setFilter('quicknotes', this.filterProxy); });
},
filterProxy: function(query) {
filter(query);
},
setFilter: function(newFilter) {
filter = newFilter;
}
};
SearchProxy.setFilter(filter);
OC.Plugins.register('OCA.Search', SearchProxy);
/*
* Create modules
*/
var notes = new Notes(OC.generateUrl('/apps/quicknotes/notes')); var notes = new Notes(OC.generateUrl('/apps/quicknotes/notes'));
var view = new View(notes); var view = new View(notes);
/*
* Render loading view
*/
view.renderContent();
/*
* Loading notes and render view.
*/
notes.loadAll().done(function () { notes.loadAll().done(function () {
view.render(); view.render();
}).fail(function () { }).fail(function () {

View File

@@ -0,0 +1,33 @@
<div id="new-note-fixed">
<div>
<button type="button" id="new-note" class="icon-add">{{newNoteTxt}}</button>
</div>
</div>
<li id="all-notes">
<a href="#" class="icon-home svg">
{{allNotesTxt}}
</a>
</li>
<li id="colors-folder" class="collapsible open">
<button class="collapse"></button>
<a href="#" class="icon-search svg">{{colorsTxt}}</a>
<ul>
<li style="display: flex; justify-content: center;">
<button class="circle-toolbar icon-checkmark any-color"></button>
{{#each colors}}
<button class="circle-toolbar" style="background-color: {{color}} "></button>
{{/each}}
</li>
</ul>
</li>
<li id="notes-folder" class="collapsible open">
<button class="collapse"></button>
<a href="#" class="icon-folder svg">{{notesTxt}}</a>
<ul>
{{#each notes}}
<li class="note with-menu {{#if active}}active{{/if}}" data-id="{{ id }}">
<a href="#">{{{ title }}}</a>
</li>
{{/each}}
</ul>
</li>

View File

@@ -0,0 +1,30 @@
<div class="note-grid-item">
<div class="quicknote noselect {{#if active}}note-active{{/if}} {{#if isshared}}shared{{/if}} {{#if sharedwith}}shareowner{{/if}}" style="background-color: {{color}}" data-id="{{ id }}" data-timestamp="{{ timestamp }}" >
{{#if isshared}}
<div>
<div class='icon-share shared-title' title="Shared by {{ userid }}"></div>
<div class='note-title'>
{{{ title }}}
</div>
</div>
<div id='content' class='note-content'>
{{{ content }}}
</div>
{{else}}
<div>
<div class="icon-delete hide-delete-icon icon-delete-note" title="Delete"></div>
<!--
{{#if sharedwith}}
<div class='icon-share shared-title-owner' title="Shared with {{ sharedwith }}"></div>
{{/if}}
-->
<div class='note-title'>
{{{ title }}}
</div>
</div>
<div class='note-content'>
{{{ content }}}
</div>
{{/if}}
</div>
</div>

View File

@@ -1,3 +1,38 @@
{{#if notes}}
<div class="notes-grid">
{{#each notes}}
<div class="note-grid-item">
<div class="quicknote noselect {{#if active}}note-active{{/if}} {{#if isshared}}shared{{/if}} {{#if sharedwith}}shareowner{{/if}}" style="background-color: {{color}}" data-id="{{ id }}" data-timestamp="{{ timestamp }}" >
{{#if isshared}}
<div>
<div class='icon-share shared-title' title="Shared by {{ userid }}"></div>
<div class='note-title'>
{{{ title }}}
</div>
</div>
<div id='content' class='note-content'>
{{{ content }}}
</div>
{{else}}
<div>
<div class="icon-delete hide-delete-icon icon-delete-note" title="Delete"></div>
<!--
{{#if sharedwith}}
<div class='icon-share shared-title-owner' title="Shared with {{ sharedwith }}"></div>
{{/if}}
-->
<div class='note-title'>
{{{ title }}}
</div>
</div>
<div class='note-content'>
{{{ content }}}
</div>
{{/if}}
</div>
</div>
{{/each}}
</div>
<div id="modal-note-div" class="hide-modal-note modal-note-background"> <div id="modal-note-div" class="hide-modal-note modal-note-background">
<div class="modal-content"> <div class="modal-content">
<div class="quicknote note-active" style="background-color: #F7EB96" data-id="-1"> <div class="quicknote note-active" style="background-color: #F7EB96" data-id="-1">
@@ -25,11 +60,33 @@
<!-- <!--
<button id='share-button'><?php p($l->t('Share'));?></button> <button id='share-button'><?php p($l->t('Share'));?></button>
--> -->
<button id='cancel-button'><?php p($l->t('Cancel')); ?></button> <button id='cancel-button'>
<button id='save-button'><?php p($l->t('Save')); ?></button> {{ cancelTxt }}
</button>
<button id='save-button'>
{{ saveTxt }}
</button>
</div> </div>
<div style="clear: both;"></div> <div style="clear: both;"></div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
{{else if loaded}}
<div class="emptycontent">
<div class="icon-edit svg"></div>
<h2>
{{ emptyMsg }}
</h2>
</div>
{{else}}
<div class="emptycontent">
<div class="icon-edit svg"></div>
<h2>
{{loadingMsg}}
</h2>
<img class="loadingimport" src="{{loadingIcon}}"/>
</div>
{{/if}}

View File

@@ -1,5 +1,6 @@
<?php <?php
vendor_script('quicknotes', 'handlebars'); vendor_script('quicknotes', 'handlebars');
script('quicknotes', 'templates');
vendor_script('quicknotes', 'isotope.pkgd'); vendor_script('quicknotes', 'isotope.pkgd');
vendor_script('quicknotes', 'medium-editor'); vendor_script('quicknotes', 'medium-editor');
vendor_style('quicknotes', 'medium-editor'); vendor_style('quicknotes', 'medium-editor');

View File

@@ -1,16 +1 @@
<script id="content-tpl" type="text/x-handlebars-template">
{{#if notes}}
<div class="notes-grid">
{{#each notes}}
<?php print_unescaped($this->inc('part.note')); ?>
{{/each}}
</div>
<?php print_unescaped($this->inc('part.note-modal-editable')); ?>
{{else}}
<div class="emptycontent">
<div class="icon-folder"></div>
<?php p($l->t('Nothing here. Take your quick notes.')); ?>
</div>
{{/if}}
</script>
<div id="div-content"></div> <div id="div-content"></div>

View File

@@ -1,50 +1 @@
<!-- translation strings -->
<div style="display:none" id="new-note-string"><?php p($l->t('New note')); ?></div>
<script id="navigation-tpl" type="text/x-handlebars-template">
<div id="new-note-fixed">
<div><button type="button" id="new-note" class="icon-add"><?php p($l->t('New note'));?></button></div>
</div>
<li id="all-notes"><a href="#" class="icon-home svg"><?php p($l->t('All notes')); ?></a></li>
<!--
<li id="shared-with-you"><a href="#" class="icon-share svg"><?php p($l->t('Shared with you')); ?></a></li>
<li id="shared-by-you"><a href="#" class="icon-share svg"><?php p($l->t('Shared with others')); ?></a></li>
-->
<li id="colors-folder" class="collapsible open">
<button class="collapse"></button>
<a href="#" class="icon-search svg"><?php p($l->t('Colors')); ?></a>
<ul>
<li style="display: flex; justify-content: center;">
<button class="circle-toolbar icon-checkmark any-color"></button>
{{#each colors}}
<button class="circle-toolbar" style="background-color: {{color}} "></button>
{{/each}}
</li>
</ul>
</li>
<li id="notes-folder" class="collapsible open">
<button class="collapse"></button>
<a href="#" class="icon-folder svg"><?php p($l->t('Notes')); ?></a>
<ul>
{{#each notes}}
<li class="note with-menu {{#if active}}active{{/if}}" data-id="{{ id }}">
<a href="#">{{{ title }}}</a>
<!--
<div class="app-navigation-entry-utils">
<ul>
<li class="app-navigation-entry-utils-menu-button svg"><button></button></li>
</ul>
</div>
<div class="app-navigation-entry-menu">
<ul>
<li><button class="delete icon-delete svg" title="delete"></button></li>
</ul>
</div>
-->
</li>
{{/each}}
</ul>
</li>
</script>
<ul class="with-icon"></ul> <ul class="with-icon"></ul>

View File

@@ -1,22 +0,0 @@
<div class="note-grid-item">
<div class="quicknote noselect {{#if active}}note-active{{/if}} {{#if isshared}}shared{{/if}} {{#if sharedwith}}shareowner{{/if}}" style="background-color: {{color}}" data-id="{{ id }}" data-timestamp="{{ timestamp }}" >
{{#if isshared}}
<div>
<div class='icon-share shared-title' title="Shared by {{ userid }}"></div>
<div class='note-title'>{{{ title }}}</div>
</div>
<div id='content' class='note-content'>{{{ content }}}</div>
{{else}}
<div>
<div class="icon-delete hide-delete-icon icon-delete-note" title="Delete"></div>
<!--
{{#if sharedwith}}
<div class='icon-share shared-title-owner' title="Shared with {{ sharedwith }}"></div>
{{/if}}
-->
<div class='note-title'>{{{ title }}}</div>
</div>
<div class='note-content'>{{{ content }}}</div>
{{/if}}
</div>
</div>