From 59761e6412e88a206df8a57e195ecaea584b8026 Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Thu, 15 Aug 2013 01:28:29 +0200 Subject: [PATCH] Node creation, required form field styling, notification and error popups, JSDE hooks and window-contained form hooking, bugfix in form hooking, icon replacement for form submission, improve form hooking callback signature, include jQuery timing plugin --- public_html/modules/nodes/create.php | 46 ++++++++ public_html/static/css/openng.css | 76 +++++++++++++ public_html/static/js/jquery-timing.min.js | 1 + public_html/static/js/jsde.js | 15 ++- public_html/static/js/openng.js | 119 ++++++++++++++++++++- public_html/templates/index.tpl | 24 ++++- public_html/templates/nodes/create.tpl | 6 +- 7 files changed, 278 insertions(+), 9 deletions(-) create mode 100644 public_html/static/js/jquery-timing.min.js diff --git a/public_html/modules/nodes/create.php b/public_html/modules/nodes/create.php index 65780fe..1ee2257 100644 --- a/public_html/modules/nodes/create.php +++ b/public_html/modules/nodes/create.php @@ -23,5 +23,51 @@ if($router->uMethod == "get") elseif($router->uMethod == "post") { /* Process form */ + $sErrors = array(); + if(empty($_POST['name'])) + { + $sErrors[] = "You must enter a name for the new node. This name does not have to be unique."; + } + + if(empty($sErrors)) + { + $sNode = new Node(); + + $sNode->uName = $_POST['name']; + $sNode->uNotes = $_POST['notes']; + + $sNode->uTypeId = 0; + $sNode->uParentRevisionId = 0; + $sNode->uFirstRevisionId = 0; + $sNode->uUserId = 0; + $sNode->uCreationDate = time(); + $sNode->uLatestRevision = true; + + $sNode->InsertIntoDatabase(); + + /* Update the entry to refer to itself as the first revision */ + $sNode->uFirstRevisionId = $sNode->sId; + $sNode->InsertIntoDatabase(); + + $sData = array( + "result" => "success", + "message" => "Node '" . htmlspecialchars($_POST['name']) . "' created.", + "node_id" => $sNode->sId + ); + } + else + { + $sErrorList = ""; + + foreach($sErrors as $sError) + { + $sErrorList .= "
  • {$sError}
  • "; + } + + $sData = array( + "result" => "error", + "message" => "One or more form fields were not filled in correctly: " + ); + } } diff --git a/public_html/static/css/openng.css b/public_html/static/css/openng.css index 5677897..e5e00ea 100644 --- a/public_html/static/css/openng.css +++ b/public_html/static/css/openng.css @@ -162,3 +162,79 @@ textarea bottom: 0px; text-align: right; } + +i.required +{ + font-size: 10px; + margin-left: 4px; + color: rgb(159,68,74); + float: right; + margin-right: 7px; + margin-top: 2px; +} + +i.error, i.notification +{ + font-size: 19px; + margin-right: 9px !important; +} + +i.error +{ + color: #FFD2D2; +} + +i.notification +{ + color: #CBCAFF; +} + +#notification_area +{ + position: absolute; + right: 0px; + bottom: 32px; + z-index: 2147483640; +} + +.notification-header +{ + margin-right: 6px; + font-weight: bold; +} + +.notification-popup, .error-popup +{ + text-align: right; +} + +.notification-popup .notification-contents, .error-popup .notification-contents +{ + text-align: left; + display: inline-block; + border-radius: 6px; + margin-right: 19px; + margin-top: 10px; + padding: 9px 14px; + color: white; + font-size: 15px; + filter: alpha(opacity=85); + opacity: 0.85; + width: auto; +} + +.notification-popup .notification-contents +{ + background-color: #2D2D2D; +} + +.error-popup .notification-contents +{ + background-color: #371B1B; +} + +.notification-popup ul, .error-popup ul +{ + margin: 4px 0px; + padding-left: 48px; +} diff --git a/public_html/static/js/jquery-timing.min.js b/public_html/static/js/jquery-timing.min.js new file mode 100644 index 0000000..78f26e2 --- /dev/null +++ b/public_html/static/js/jquery-timing.min.js @@ -0,0 +1 @@ +(function(m,j){var d={},e=1,f=m.fn.each,k=m.fn.on||m.fn.bind,n=m.fn.off||m.fn.unbind,l={};function a(p,q){q=m(q);q.prevObject=p;var o=p.length;if(o!==q.length){return q}while(o--){if(p[o]!==q[o]){return q}}return p}function c(o){var p=[],q=o.length;while(q--){p[q]=o[q].g}return p}function h(p,w,t,s){t=t||[];var u={f:p,i:w},q=false,o,x,y;function v(A,B){A.e=false;function z(){A.k=a(A.f,A.k);A.e=true;r()}return typeof B.promise=="function"?B.promise().then(z):B.then(z,true)}function r(A){while(!q){try{q=!q;if(typeof s=="function"){s(m.makeArray(u.k||u.f))}if(u.e==false){break}if(!u.i.j){if(y&&(!t.length||t[0].b)){if(u.f&&typeof u.f.promise=="function"){u.f.promise().then(y.resolve)}else{y.resolveWith(u.f)}y=null}if(!t.length){return u.f}x=t[0].l&&t[0].l(r,u,t);if(!x){break}u=x;continue}o=u.f&&u.f[u.i.j]||l[u.i.j];if(!o){throw'no such method "'+u.i.j+'" on object ('+u.f+")"}if(o.timing&&!u.e){u.e=false;u=o.timing(r,u,t,s)||u}else{if(!o.timing&&!u.e){u.k=u.f[u.i.j].apply(u.f,u.i.c);if(t.length&&u.k&&u.k instanceof g){v(u,u.k);continue}}x={f:u.k,i:u.i.k};u.e=false;if(typeof u.d=="function"){u.d.apply(u.f,c(t))}u=x}}catch(z){q=!q;throw z}finally{q=!q}}return A}if(m.Deferred){r.promise=function(A,B){var z=(y=y||m.Deferred()).promise(B);r();return z}}return r}function g(q,r,p){this[".methods"]=r;this[".callback"]=p;this.length=0;Array.prototype.push.apply(this,m.makeArray(this._=q._=q));for(var o in q){if(!(o in g.prototype)&&typeof q[o]=="function"){this[o]=i(o)}}}if(m.Deferred){g.prototype.promise=function(o,p){if(typeof o=="object"){p=o;o=null}return(this[".callback"]&&typeof this[".callback"].promise=="function")?this[".callback"].promise(o,p):m.Deferred().resolveWith(this).promise(p)}}function i(o){return g.prototype[o]=function(){this[".methods"].j=o;this[".methods"].c=arguments;this[".methods"]=this[".methods"].k={};return this[".callback"]?this[".callback"](this,o,arguments):this}}m.each(["bind","on","one","live","delegate"],function(p,o){if(m.fn[o]){var q=m.fn[o];m.fn[o]=function(){var u,x,w,s,r,t=this;for(u=0;u1&&arguments[arguments.length-1]===m){var r="_timing"+e++;arguments[arguments.length-1]=function(){m(this).trigger(r)};return this.each().one(r).all(q.apply(this,arguments))}return q.apply(this,arguments)}}});m.each(["wait","repeat","join","then"],function(p,o){m.fn[o]=function(){var r={},q=new g(this,r,h(this,r,[],function(s){q.length=0;Array.prototype.push.apply(q,s)}));return q[o].apply(q,arguments)}});m.fn.join.timing=function(p,r){var q,o,s=r.f.length;if(typeof r.i.c[0]=="string"){q=r.i.c[0];if(typeof r.i.c[1]=="function"){r.d=r.i.c[1]}else{o=r.i.c[1];r.d=r.i.c[2]}}else{if(typeof r.i.c[0]=="function"){r.d=r.i.c[0]}else{o=r.i.c[0];r.d=r.i.c[1]}}r.k=r.f;r.e=!s;if(o){r.f.promise(q==null?"fx":q).then(function(){r.e=true;p()})}else{r.f.queue(q==null?"fx":q,function(t){r.e=!--s;p();t()})}};m.fn.then.timing=function(o,p){p.d=p.i.c[0];p.k=p.f;p.e=true;if(p.i.c[1]){Array.prototype.shift.apply(p.i.c)}};m.fn.wait.timing=function(s,t,u){var r,o,v,p=t.f;r=t.i.c[0];t.d=t.i.c[1];function w(){n.call(o?n.call(p,o,w):p,"unwait",q);t.e=true;t.k=a(t.f,t.k);s()}function q(x,y){n.call(o?n.call(m(this),o,w):m(this),"unwait",q);p=p.not(this);if(!y){t.k=t.k.not(this)}if(!p.length){t.e=t.k.length;t.k=a(t.f,t.k);j.clearTimeout(v);t={f:p}}s()}k.call(p,"unwait",q);t.k=p;if(r==null||r==m){r=p}if(typeof r=="function"){r=r.apply(p,c(u))}if(typeof r=="string"){k.call(p,o=r,w)}else{if(r&&typeof r.promise=="function"){r.promise().then(w)}else{if(r&&typeof r.then=="function"){r.then(w,true)}else{v=j.setTimeout(w,Math.max(0,r))}}}};m.fn.each=function(q){if(!q||q===m){var p={},o=new g(this,p,h(this,p,[],function(r){o.length=0;Array.prototype.push.apply(o,r)}));return o.each(q)}return f.apply(this,arguments)};m.fn.each.timing=function(r,v,w,u){if(v.i.c[0]&&v.i.c[0]!==m){v.e=true;v.k=f.apply(v.f,v.i.c);return}var B=Math.max(v.f.length,1),p=0,y,s,t,A=[],z=[],x=m.extend({},v.f),q=v.i.c[0]===m;if(q){j.setTimeout(function(){t=true;r()},0)}function o(){if(q){if(p=s-1}if(s){r.e=true;r.k=r.f;q.shift().n(s)}else{if(p){q[0].k=r.f}r=q[0];r.g++;r.n(s);return r}};new g(l);m.each(["unwait","unrepeat"],function(p,o){m.fn[o]=function(){return this.trigger(o,arguments)}});m.each(["wait","repeat","join","then","unwait","unrepeat"],function(p,o){m[o]=function(){var q=typeof arguments[0]=="string"?Array.prototype.shift.apply(arguments):"";return m.fn[o].apply(d[q]=(d[q]||m("
    ").text(q)),arguments)}});function b(r,u,q){if(typeof r=="string"){q=new Function("x","return ["+r+"\n,x]");r=function(w,v){v=q(w);p.x=v[1];return v[0]}}var o=typeof u=="function",t=typeof r=="function",p=function(v){if(arguments.length==1){p.x=v;if(o){u(v)}}else{return s()}};function s(v){v=o?u():p.x;return t?r(v):v}p.x=0;p._={toString:p.$=p.toString=s.toString=s};p.mod=function(v){return b(function(w){return w%v},p)};p.add=function(v){return b(function(w){return w+v},p)};p.neg=function(){return b("-x",p)};p.$$=p.X=function(v){return b(v,p)};m.each("abcdefghij",function(v,w){p[v]=p[w]=function(){p(arguments[v])}});return p}j.$$=m.$$=m.X=b;m.fn.$=function(){var o=m.apply(j,arguments);o.prevObject=this;return o}})(jQuery,window); \ No newline at end of file diff --git a/public_html/static/js/jsde.js b/public_html/static/js/jsde.js index 59612f5..8146009 100755 --- a/public_html/static/js/jsde.js +++ b/public_html/static/js/jsde.js @@ -114,6 +114,11 @@ function JsdeWindow(options) } this.BringToForeground(); + + if(typeof jsde_creation_hook === "function") + { + jsde_creation_hook(this); + } } JsdeWindow.prototype.BringToForeground = function() @@ -173,8 +178,14 @@ JsdeWindow.prototype.SetSize = function(width, height) JsdeWindow.prototype.SetContents = function(html) { - console.log("set contents", html, this); - return $(this._inner).html(html); + var returnval = $(this._inner).html(html); + + if(typeof jsde_contents_hook === "function") + { + jsde_contents_hook(this); + } + + return returnval; } JsdeWindow.prototype.SetTitle = function(html) diff --git a/public_html/static/js/openng.js b/public_html/static/js/openng.js index 9f3f56b..d6378a3 100644 --- a/public_html/static/js/openng.js +++ b/public_html/static/js/openng.js @@ -1,3 +1,20 @@ +var jsde_creation_hook = function(win) +{ + /* This function is a hook that is called after each creation of + * a JSDE window. */ + +} + +var jsde_contents_hook = function(win) +{ + /* This function is a hook that is called after each time + * content is set in a JSDE window. */ + placeHooksForWindow(win); +} + +notification_popups = []; +error_popups = []; + function hookSubmitEvent(form, callback, error) { /* Hooks a form to be submitted via AJAX, executing the given @@ -11,18 +28,48 @@ function hookSubmitEvent(form, callback, error) form.each(function(index){ var element = $(this); - var method = element.attr("method").toUpperCase(); + var method = element.attr("method"); var target = element.attr("action"); + if(typeof method !== "undefined") + { + method = method.toUpperCase(); + } + else + { + method = "GET"; + } + element.submit(function(){ + var submit_button = element.find("button[type=submit]"); + var submit_icon = submit_button.data("submit-icon"); + + if(typeof submit_icon !== "undefined") + { + /* First we will try to replace an existing icon + * in the button. If there is no icon yet, the + * entire contents of the button will be replaced + * with the submission icon. */ + var current_icon = submit_button.find("i"); + + if(current_icon.length == 0) + { + submit_button.html(""); + current_icon = element.find("i"); + } + + current_icon.removeClass().addClass(submit_icon); + } + var formdata = element.serialize(); console.log(formdata); $.ajax({ type: method, url: target, data: formdata, - success: callback, - error: error + dataType: "json", + success: function(data, xhr){ console.log(data); callback(element, data, xhr); }, + error: function(data, xhr, err){ error(element, data, xhr, err); } }); return false; @@ -30,6 +77,69 @@ function hookSubmitEvent(form, callback, error) }); } +function placeHooksForWindow(win) +{ + console.log(); + $(win._outer).find("form").each(function(){ + var callback = $(this).data("hook-callback"); + + if(typeof callback !== "undefined") + { + console.log("Hooking", this, "using callback", callback); + hookSubmitEvent($(this), window[callback]); + } + }); +} + +function callbackNodeCreated(form, data) +{ + if(data.result == "success") + { + spawnNotification(data.message); + var node_id = data.node_id; + + form.getWindow().Close(); + + new JsdeWindow({ + width: 480, + height: 300, + x: 100, + y: 100, + title: "Node lookup", + contents: "Loading...", + source_url: "/nodes/" + node_id + }); + } + else if(data.result == "error") + { + spawnError(data.message); + } +} + +function spawnNotification(message) +{ + var popup = spawnPopup(message, "notification"); + notification_popups.push(popup); +} + +function spawnError(message) +{ + var popup = spawnPopup(message, "error"); + error_popups.push(popup); +} + +function spawnPopup(message, template) +{ + var popup = $("#jsde_templates").find(".template_" + template).clone().removeClass("template_notification template_error"); + popup.find(".message").html(message.replace("\n", "
    ")); + popup.hide(); + popup.prependTo("#notification_area"); + + popup.fadeIn(300).wait(5000).fadeOut(400, $).remove(); + + return popup +} + $(function(){ hookSubmitEvent($("#form_search")); @@ -56,4 +166,7 @@ $(function(){ contents: "Loading...", source_url: "/intro" }); + + spawnNotification("Test notification"); + spawnError("Test error"); }); diff --git a/public_html/templates/index.tpl b/public_html/templates/index.tpl index 208a366..2bc0c4a 100644 --- a/public_html/templates/index.tpl +++ b/public_html/templates/index.tpl @@ -5,6 +5,7 @@ +