diff options
author | 2011-08-29 02:22:34 +0200 | |
---|---|---|
committer | 2011-08-29 02:22:34 +0200 | |
commit | d99bff6353aac107b1ce2174bfd9c6fc87892cd8 (patch) | |
tree | b8f480ce5c2912e9afd62529cbbecc50519d6dad /app/assets | |
parent | Add Template model and Admin::TemplateController for managing templates (diff) | |
download | glsamaker-d99bff6353aac107b1ce2174bfd9c6fc87892cd8.tar.gz glsamaker-d99bff6353aac107b1ce2174bfd9c6fc87892cd8.tar.bz2 glsamaker-d99bff6353aac107b1ce2174bfd9c6fc87892cd8.zip |
Implement the templating system
Templates can contain [placeholders] that are automatically selected when a user clicks at the appropriate place in a text field
Diffstat (limited to 'app/assets')
-rw-r--r-- | app/assets/images/icons/next.png | bin | 0 -> 658 bytes | |||
-rw-r--r-- | app/assets/images/icons/template.png | bin | 0 -> 630 bytes | |||
-rw-r--r-- | app/assets/javascripts/glsamaker_edit.js | 90 | ||||
-rw-r--r-- | app/assets/javascripts/glsamaker_misc.js | 75 | ||||
-rw-r--r-- | app/assets/stylesheets/screen.css | 8 |
5 files changed, 171 insertions, 2 deletions
diff --git a/app/assets/images/icons/next.png b/app/assets/images/icons/next.png Binary files differnew file mode 100644 index 0000000..5102071 --- /dev/null +++ b/app/assets/images/icons/next.png diff --git a/app/assets/images/icons/template.png b/app/assets/images/icons/template.png Binary files differnew file mode 100644 index 0000000..ed7ec0e --- /dev/null +++ b/app/assets/images/icons/template.png diff --git a/app/assets/javascripts/glsamaker_edit.js b/app/assets/javascripts/glsamaker_edit.js index d74f297..cc77621 100644 --- a/app/assets/javascripts/glsamaker_edit.js +++ b/app/assets/javascripts/glsamaker_edit.js @@ -80,7 +80,7 @@ GLSAMaker.editing.packages = function() { return; } - var td = ref.up(".entry") + var td = ref.up(".entry"); Effect.Fade(td, { duration: .75, @@ -90,4 +90,92 @@ GLSAMaker.editing.packages = function() { }); } }; +}(); + +GLSAMaker.editing.templates = function() { + return { + /** + * Displays a drop down menu to select a template to append + */ + dropdown : function(button, target) { + var div = $('templates-' + target); + + if (!div) { + return; + } + + // Close the popup if it's already open + if (div.getStyle('display') != 'none') { + GLSAMaker.editing.templates.close(div); + return; + } + + var btn_layout = button.getLayout(); + + div.setStyle({ + position: 'absolute', + right: btn_layout.get('right') + "px", + top: btn_layout.get('top') + btn_layout.get('height') + 5 + "px" + }); + + Effect.SlideDown(div, { + duration: .15 + }); + }, + /** + * Closes a popup + * + * @param target The popup to close + */ + close : function(target) { + Effect.SlideUp(target, { + duration: .2 + }); + }, + /** + * Observes a field for clicks into template fields and sets the + * @param elem + */ + observeClick : function(elem) { + elem.observe('click', function(event) { + var before = '['; + var after = ']'; + + var selection_info = GLSAMaker.misc.getInputSelection(this); + var text = this.getValue(); + + // If the user clicked and did not select + if (selection_info.start == selection_info.end) { + var text_before = text.substring(0, selection_info.start); + var text_after = text.substring(selection_info.end, text.length - 1); + + // check if there is any template before this + var pos_prev = text_before.search(GLSAMaker.misc.escapeRegExp(after)); + var pos_comp = 0; + + while (pos_prev > 0) { + pos_comp += pos_prev; + text_before = text_before.slice(pos_prev); + pos_prev = text_before.search(GLSAMaker.misc.escapeRegExp(after)); + } + + var pos_before = text_before.search(GLSAMaker.misc.escapeRegExp(before)); + if (pos_before == -1) { + return; + } + + // pos_before is our selection start. + var pos_after = text_after.search(GLSAMaker.misc.escapeRegExp(after)); + if (pos_after == -1) { + return; + } + + pos_before += pos_comp; + pos_after += selection_info.end + 1; + + GLSAMaker.misc.setInputSelection(this, {start: pos_before, end: pos_after}); + } + }) + } + }; }();
\ No newline at end of file diff --git a/app/assets/javascripts/glsamaker_misc.js b/app/assets/javascripts/glsamaker_misc.js index 187cf61..fb04be3 100644 --- a/app/assets/javascripts/glsamaker_misc.js +++ b/app/assets/javascripts/glsamaker_misc.js @@ -9,7 +9,80 @@ if (typeof GLSAMaker == "undefined" || !GLSAMaker) { if (typeof GLSAMaker.misc == "undefined" || !GLSAMaker.misc) { GLSAMaker.misc = function() { - return {}; + return { + /** + * Find out the selection position in a text field + * via: http://stackoverflow.com/questions/4928586/get-caret-position-in-html-input + * + * @param el + */ + getInputSelection : function(el) { + var start = 0, end = 0, normalizedValue, range, + textInputRange, len, endRange; + + if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { + start = el.selectionStart; + end = el.selectionEnd; + } else { + range = document.selection.createRange(); + + if (range && range.parentElement() == el) { + len = el.value.length; + normalizedValue = el.value.replace(/\r\n/g, "\n"); + + // Create a working TextRange that lives only in the input + textInputRange = el.createTextRange(); + textInputRange.moveToBookmark(range.getBookmark()); + + // Check if the start and end of the selection are at the very end + // of the input, since moveStart/moveEnd doesn't return what we want + // in those cases + endRange = el.createTextRange(); + endRange.collapse(false); + + if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { + start = end = len; + } else { + start = -textInputRange.moveStart("character", -len); + start += normalizedValue.slice(0, start).split("\n").length - 1; + + if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { + end = len; + } else { + end = -textInputRange.moveEnd("character", -len); + end += normalizedValue.slice(0, end).split("\n").length - 1; + } + } + } + } + + return { + start: start, + end: end + }; + }, + /** + * Sets the caret position of a control + * @param ctrl + * @param pos + */ + setInputSelection: function (ctrl, data) { + if (ctrl.setSelectionRange) { + ctrl.focus(); + ctrl.setSelectionRange(data.start, data.end); + } + else if (ctrl.createTextRange) { + var range = ctrl.createTextRange(); + range.collapse(true); + range.moveEnd('character', data.end); + range.moveStart('character', data.start); + range.select(); + } + }, + escapeRegExp : function(text) { + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + } + }; }(); } diff --git a/app/assets/stylesheets/screen.css b/app/assets/stylesheets/screen.css index 81a47ff..77b5c7f 100644 --- a/app/assets/stylesheets/screen.css +++ b/app/assets/stylesheets/screen.css @@ -386,6 +386,14 @@ div.box .box-actions { width: 100%; } + +/** popups **/ +div.popup { + background-color: #8875B0; + opacity: .9; + padding: .2em; +} + /** leftright **/ div#right { width: 40%; |