summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Legler <alex@a3li.li>2011-08-29 02:22:34 +0200
committerAlex Legler <alex@a3li.li>2011-08-29 02:22:34 +0200
commitd99bff6353aac107b1ce2174bfd9c6fc87892cd8 (patch)
treeb8f480ce5c2912e9afd62529cbbecc50519d6dad /app/assets
parentAdd Template model and Admin::TemplateController for managing templates (diff)
downloadglsamaker-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.pngbin0 -> 658 bytes
-rw-r--r--app/assets/images/icons/template.pngbin0 -> 630 bytes
-rw-r--r--app/assets/javascripts/glsamaker_edit.js90
-rw-r--r--app/assets/javascripts/glsamaker_misc.js75
-rw-r--r--app/assets/stylesheets/screen.css8
5 files changed, 171 insertions, 2 deletions
diff --git a/app/assets/images/icons/next.png b/app/assets/images/icons/next.png
new file mode 100644
index 0000000..5102071
--- /dev/null
+++ b/app/assets/images/icons/next.png
Binary files differ
diff --git a/app/assets/images/icons/template.png b/app/assets/images/icons/template.png
new file mode 100644
index 0000000..ed7ec0e
--- /dev/null
+++ b/app/assets/images/icons/template.png
Binary files differ
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%;