Template error
" + ex.MessageAsHtml(), DotNetNuke.UI.Skins.Controls.ModuleMessage.ModuleMessageType.RedError); @@ -130,6 +146,5 @@ private void RenderJsonException(InvalidJsonFileException ex, ModuleInfo module) } LoggingUtils.ProcessLogFileException(this, module, ex); } - } } \ No newline at end of file diff --git a/OpenContent/ShareTemplate.ascx b/OpenContent/ShareTemplate.ascx index c47e874f..41f3a672 100644 --- a/OpenContent/ShareTemplate.ascx +++ b/OpenContent/ShareTemplate.ascx @@ -24,6 +24,8 @@\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-image"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-radio"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-select"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-text"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-textarea"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-url"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "target=\"" - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTarget)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\""; - return buffer; - } - -function program3(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program5(depth0,data) { - - var stack1, helper; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - return escapeExpression(stack1); - } - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n " - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\n "; - return buffer; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\n "; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program4(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program6(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper, options; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - - return "type=\"submit\""; - } - -function program7(depth0,data) { - - - return "type=\"reset\""; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-actionbar"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } - -function program4(depth0,data) { - - var stack1, helper; - if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { return stack1; } - else { return ''; } - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-item"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper, options; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - - return "readonly=\"readonly\""; - } - -function program3(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "name=\""; - if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "data-" - + escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\"" - + escapeExpression((typeof depth0 === functionType ? depth0.apply(depth0) : depth0)) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n\n "; - stack1 = helpers.each.call(depth0, (depth0 && depth0.checkboxOptions), {hash:{},inverse:self.noop,fn:self.programWithDepth(2, program2, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - return buffer; - } -function program2(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"] = this["HandlebarsPrecompiled"]["bootstrap-display"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"]["control-radio"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"] = this["HandlebarsPrecompiled"]["bootstrap-display"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"]["control-select"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"] = this["HandlebarsPrecompiled"]["bootstrap-display"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"]["control"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program4(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program6(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"] = this["HandlebarsPrecompiled"]["bootstrap-display"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-display"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"] = this["HandlebarsPrecompiled"]["bootstrap-edit"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"]["container-grid"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - - return " btn-group"; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n\n "; - stack1 = (helper = helpers.compare || (depth1 && depth1.compare),options={hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data},helper ? helper.call(depth0, ((stack1 = (depth1 && depth1.options)),stack1 == null || stack1 === false ? stack1 : stack1.toolbarStyle), "link", options) : helperMissing.call(depth0, "compare", ((stack1 = (depth1 && depth1.options)),stack1 == null || stack1 === false ? stack1 : stack1.toolbarStyle), "link", options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - stack1 = (helper = helpers.compare || (depth1 && depth1.compare),options={hash:{},inverse:self.noop,fn:self.programWithDepth(6, program6, data, depth1),data:data},helper ? helper.call(depth0, ((stack1 = (depth1 && depth1.options)),stack1 == null || stack1 === false ? stack1 : stack1.toolbarStyle), "button", options) : helperMissing.call(depth0, "compare", ((stack1 = (depth1 && depth1.options)),stack1 == null || stack1 === false ? stack1 : stack1.toolbarStyle), "button", options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - return buffer; - } -function program4(depth0,data) { - - var buffer = "", stack1; - buffer += "\n " - + escapeExpression(((stack1 = (depth0 && depth0.label)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\n "; - return buffer; - } - -function program6(depth0,data,depth2) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } - -function program9(depth0,data) { - - var stack1, helper; - if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { return stack1; } - else { return ''; } - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"] = this["HandlebarsPrecompiled"]["bootstrap-edit"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"]["container"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + " "; - return buffer; - } - -function program4(depth0,data) { - - - return "\n \n "; - } - -function program6(depth0,data) { - - - return "\n \n "; - } - -function program8(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program9(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program11(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"] = this["HandlebarsPrecompiled"]["bootstrap-edit"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"]["control-upload-partial-download"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"] = this["HandlebarsPrecompiled"]["bootstrap-edit"] || {}; -this["HandlebarsPrecompiled"]["bootstrap-edit"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -/** - * Using fork: - * https://github.com/kcmoot/Base.js-Fork/blob/master/build/base.js - */ -(function (root, factory) { - /* - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define([], function () { - return (root.returnExportsGlobal = factory()); - }); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like enviroments that support module.exports, - // like Node. - module.exports = factory(); - } else { - */ - root['Base'] = factory(); - /* - } - */ -}(this, function () { - - /** - * Base.js, version 1.1a - * Copyright 2006-2010, Dean Edwards - * License: http://www.opensource.org/licenses/mit-license.php - * - * Modified by the Nerdery for improved performance and various bugfixes - */ - - /** - * Function type - * - * @type String - * @ignore - * @final - */ - var TYPE_FUNCTION = 'function'; - - /** - * Object type - * - * @type String - * @ignore - * @final - */ - var TYPE_OBJECT = 'object'; - - /** - * String type - * - * @type String - * @ignore - * @final - */ - var TYPE_STRING = 'string'; - - /** - * Flag to determine if we are currently creating a clean prototype of a class - * - * @type Boolean - * @private - * @ignore - */ - var _prototyping = false; - - /** - * Method to extend manually - do not do automatically - * - * @type Array - * @private - * @ignore - */ - var _hiddenMethods = ['constructor', 'toString', 'valueOf']; - - /** - * Lenth of hidden methods array - * - * @type Number - * @private - * @ignore - */ - var _hiddenMethodsLength = _hiddenMethods.length; - - /** - * Regex to find any calls to a parent method - * - * @type RegExp - * @private - * @ignore - */ - var _superMethodRegex = /\bbase\b/; - - /** - * Blank function - * - * @type Function - * @private - * @ignore - */ - var _blankFunction = function() {}; - - /** - * Prototype default values. When extending methods, if both sources have these values, do not copy them. - * - * @type Object - * @private - * @ignore - */ - var _prototypeDefaults = { toSource: null, base: _blankFunction }; - - /** - * BaseLib class - * - * A library to create a more traditional OOP interface for developers to work with - * - * @class Lib.Base.Base - * - * @constructor - */ - var Base = function() {}; - - /** - * Subclass a class - * - * @method extend - * @param {Object} [instanceMethods] Instance members/methods - * @param {Object} [staticMethods] Static members/methods - * @return {Function} - * @static - */ - Base.extend = function(instanceMethods, staticMethods) { // subclass - var extend = Base.prototype.extend; - - // build the prototype - _prototyping = true; - - var proto = new this(); - extend.call(proto, instanceMethods); - - // call this method from any other method to invoke that method's ancestor - proto.base = _prototypeDefaults.base; - - _prototyping = false; - - // create the wrapper for the constructor function - var constructor = proto.constructor; - var klass = proto.constructor = function() { - if (!_prototyping) { - // instantiation - if (this && (this._constructing || this.constructor === klass)) { - this._constructing = true; - constructor.apply(this, arguments); - this._constructing = false; - - // casting - } else if (arguments.length) { - Base.cast.apply(klass, arguments); - } - } - }; - // build the class interface - extend.call(klass, this); - klass.ancestor = this; - klass.prototype = proto; - - /** - * Return original method - * - * @method valueOf - * @param {String} [type] - * @return Function - * @static - */ - klass.valueOf = function(type) { - return (type === TYPE_OBJECT) ? klass : constructor.valueOf(); - }; - extend.call(klass, staticMethods); - - // if static init method exists, call it - if (typeof klass.init === TYPE_FUNCTION) { - klass.init(); - } - - return klass; - }; - - /** - * @method extend - * @param {String|Object} source - * @param {Function} [value] - * @chainable - */ - Base.prototype.extend = function(source, value) { - // extending with a name/value pair - if (typeof source === TYPE_STRING && arguments.length > 1) { - var ancestor = this[source]; - if ( - ancestor && - // overriding a method? - (typeof value === TYPE_FUNCTION) && - // the valueOf() comparison is to avoid circular references - (!ancestor.valueOf || ancestor.valueOf() !== value.valueOf()) && - _superMethodRegex.test(value) - ) { - // get the underlying method - var method = value.valueOf(); - - // override - value = function() { - var returnValue; - var previous = this.base || _prototypeDefaults.base; - this.base = ancestor; - if (arguments.length === 0) { - returnValue = method.call(this); - } else { - returnValue = method.apply(this, arguments); - } - this.base = previous; - return returnValue; - }; - - // point to the underlying method - value.valueOf = function(type) { - return (type === TYPE_OBJECT) ? value : method; - }; - value.toString = Base.toString; - } - this[source] = value; - - // extending with an object literal - } else if (source) { - var extend = Base.prototype.extend; - - // if this object has a customised extend method then use it - if (!_prototyping && typeof this !== TYPE_FUNCTION) { - extend = this.extend || extend; - } - - // do hidden methods separately - // if we are prototyping then include the constructor - var i = _prototyping ? 0 : 1; - var key; - for (; i < _hiddenMethodsLength; i++) { - key = _hiddenMethods[i]; - if (source[key] !== _prototypeDefaults[key]) { - extend.call(this, key, source[key]); - } - } - - // copy each of the source object's properties to this object - for (key in source) { - if (!_prototypeDefaults[key]) { - extend.call(this, key, source[key]); - } - } - } - - return this; - }; - - // initialise - Base = Base.extend({ - - /** - * Default static base method - * - * @method base - * @ignore - */ - base: _prototypeDefaults.base - - }, { - - /** - * Parent object/class - * - * @property ancestor - * @type Object - * @static - * @ignore - */ - ancestor: Object, - - /** - * Base.js version - * - * @property version - * @type String - * @static - * @ignore - */ - version: '1.1', - - /** - * Extend current class into another object or class. - * - * If an object with no prototype is passed, only prototype methods - * will be cast EXCEPT for the constructor. - * - * If an a class (with constructor) is passed, both static and - * prototype methods will be cast EXCEPT for the constructor. - * - * @method cast - * @param {Object|Function} class* Classes or objects to cast - * @chainable - * @static - */ - cast: function() { - var i = 0; - var length = arguments.length; - var extend; - var caster; - - for (; i < length; i++) { - caster = arguments[i]; - extend = caster.extend || Base.prototype.extend; - - // cast prototype and static methods - if (typeof caster === TYPE_FUNCTION) { - extend = caster.prototype.extend || Base.prototype.extend; - extend.call(caster.prototype, this.prototype); - extend.call(caster, this); - caster.ancestor = this; - - // cast only prototype methods - } else { - extend.call(caster, this.prototype); - } - } - - return this; - }, - - /** - * Implement a class into the current class. - * - * All prototype and static properties will be extended into - * `this` EXCEPT for the constructor. - * - * @method implement - * @param {Object|Function} class* Classes or objects to cast - * @chainable - * @static - */ - implement: function() { - for (var i = 0; i < arguments.length; i++) { - this.cast.call(arguments[i], this); - } - - return this; - }, - - /** - * Get string value of class - * - * @method toString - * @return String - * @static - */ - toString: function() { - return this.valueOf() + ''; - } - - }); - - return Base; - - -})); -/*jshint -W004 */ // duplicate variables -/*jshint -W083 */ // inline functions are used safely -/** - * Alpaca forms engine for jQuery - */ -(function($) { - - /** - * Renders an Alpaca field instance that is bound to a DOM element. - * - * The basic syntax is: - * - *
- *
- * Alpaca(el, config);
- *
- *
- *
- * The full syntax is:
- *
- *
- *
- * Alpaca(el, {
- * "data" : {Any} field data (optional),
- * "schema": {Object} field schema (optional),
- * "options" : {Object} field options (optional),
- * "view": {Object|String} field view (object or id reference) (optional),
- * "render": {Function} callback function for replacing default rendering method (optional),
- * "postRender": {Function} callback function for post-rendering (optional),
- * "error": {Function} callback function for error handling (optional),
- * "connector": {Alpaca.Connector} connector for retrieving or storing data, schema, options, view and templates. (optional)
- * });
- *
- *
- *
- * @returns {*}
- */
- var Alpaca = function()
- {
- var args = Alpaca.makeArray(arguments);
- if (args.length === 0) {
- // illegal
- return Alpaca.throwDefaultError("You must supply at least one argument. This argument can either be a DOM element against which Alpaca will generate a form or it can be a function name. See http://www.alpacajs.org for more details.");
- }
-
- // element is the first argument (either a string or a DOM element)
- var el = args[0];
- if (el && Alpaca.isString(el)) {
- el = $("#" + el);
- }
-
- // other arguments we may want to figure out
- var data = null;
- var schema = null;
- var options = null;
- var view = null;
- var callback = null;
- var renderedCallback = null;
- var errorCallback = null;
- var connector = null;
- var notTopLevel = false;
- var initialSettings = {};
-
- // if these options are provided, then data, schema, options and source are loaded via connector
- var dataSource = null;
- var schemaSource = null;
- var optionsSource = null;
- var viewSource = null;
-
- // hands back the field instance that is bound directly under the element el
- var findExistingAlpacaBinding = function()
- {
- var existing = null;
-
- var topElements = $(el).find(":first");
- if (topElements.length > 0)
- {
- // does a field binding exist?
- var fieldId = $(topElements[0]).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var _existing = Alpaca.fieldInstances[fieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- else
- {
- // does a form binding exist?
- var formId = $(topElements[0]).attr("data-alpaca-form-id");
- if (formId)
- {
- var subElements = $(topElements[0]).find(":first");
- if (subElements.length > 0)
- {
- var subFieldId = $(subElements[0]).attr("data-alpaca-field-id");
- if (subFieldId)
- {
- var _existing = Alpaca.fieldInstances[subFieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- }
- }
- }
- }
-
- return existing;
- };
-
- var specialFunctionNames = ["get", "exists", "destroy"];
- var isSpecialFunction = (args.length > 1 && Alpaca.isString(args[1]) && (specialFunctionNames.indexOf(args[1]) > -1));
-
- var existing = findExistingAlpacaBinding();
- if (existing || isSpecialFunction)
- {
- if (isSpecialFunction)
- {
- // second argument must be a special function name
- var specialFunctionName = args[1];
- if ("get" === specialFunctionName) {
- return existing;
- }
- else if ("exists" === specialFunctionName) {
- return (existing ? true : false);
- }
- else if ("destroy" === specialFunctionName) {
- existing.destroy();
- return;
- }
-
- return Alpaca.throwDefaultError("Unknown special function: " + specialFunctionName);
- }
-
- return existing;
- }
- else
- {
- var config = null;
-
- // just a dom element, no other args?
- if (args.length === 1)
- {
- // grab the data inside of the element and use that for config
- var jsonString = $(el).text();
-
- config = JSON.parse(jsonString);
- $(el).html("");
- }
- else
- {
- if (Alpaca.isObject(args[1]))
- {
- config = args[1];
- }
- else if (Alpaca.isFunction(args[1]))
- {
- config = args[1]();
- }
- else
- {
- config = {
- "data": args[1]
- };
- }
- }
-
- if (!config)
- {
- return Alpaca.throwDefaultError("Unable to determine Alpaca configuration");
- }
-
- data = config.data;
- schema = config.schema;
- options = config.options;
- view = config.view;
- callback = config.render;
- if (config.callback) {
- callback = config.callback;
- }
- renderedCallback = config.postRender;
- errorCallback = config.error;
- connector = config.connector;
-
- // sources
- dataSource = config.dataSource;
- schemaSource = config.schemaSource;
- optionsSource = config.optionsSource;
- viewSource = config.viewSource;
-
- // other
- if (config.ui) {
- initialSettings["ui"] = config.ui;
- }
- if (config.type) {
- initialSettings["type"] = config.type;
- }
- if (!Alpaca.isEmpty(config.notTopLevel)) {
- notTopLevel = config.notTopLevel;
- }
- }
-
- // if no error callback is provided, we fall back to a browser alert
- if (Alpaca.isEmpty(errorCallback)) {
- errorCallback = Alpaca.defaultErrorCallback;
- }
-
- if (Alpaca.isEmpty(connector)) {
- var ConnectorClass = Alpaca.getConnectorClass("default");
- connector = new ConnectorClass("default");
- }
-
- // For second or deeper level of fields, default loader should be the one to do loadAll
- // since schema, data, options and view should have already been loaded.
- // Unless we want to load individual fields (other than the templates) using the provided
- // loader, this should be good enough. The benefit is saving time on loader format checking.
-
- var loadAllConnector = connector;
-
- if (notTopLevel) {
- var LoadAllConnectorClass = Alpaca.getConnectorClass("default");
- loadAllConnector = new LoadAllConnectorClass("default");
- }
-
- if (!options) {
- options = {};
- }
-
- // resets the hideInitValidationError back to default state after first render
- var _resetInitValidationError = function(field)
- {
- // if this is the top-level alpaca field, then we call for validation state to be recalculated across
- // all child fields
- if (!field.parent)
- {
- // final call to update validation state
- // only do this if we're not supposed to suspend initial validation errors
- if (!field.hideInitValidationError)
- {
- field.refreshValidationState(true);
- }
-
- // force hideInitValidationError to false for field and all children
- if (field.view.type !== 'view')
- {
- Alpaca.fieldApplyFieldAndChildren(field, function(field) {
-
- // set to false after first validation (even if in CREATE mode, we only force init validation error false on first render)
- field.hideInitValidationError = false;
-
- });
- }
- }
- };
-
- // wrap rendered callback to allow for UI treatment (dom focus, etc)
- var _renderedCallback = function(field)
- {
- // if top level, apply a unique observable scope id
- if (!field.parent)
- {
- field.observableScope = Alpaca.generateId();
- }
-
- // if top level and focus has not been specified, then auto-set
- if (Alpaca.isUndefined(options.focus) && !field.parent) {
- options.focus = Alpaca.defaultFocus;
- }
-
- // auto-set the focus?
- if (options && options.focus)
- {
- window.setTimeout(function() {
-
- var doFocus = function(__field)
- {
- __field.suspendBlurFocus = true;
- __field.focus();
- __field.suspendBlurFocus = false;
- };
-
- if (options.focus)
- {
- if (field.isControlField && field.isAutoFocusable())
- {
- // just focus on this one
- doFocus(field);
- }
- else if (field.isContainerField)
- {
- // if focus = true, then focus on the first child control if it is auto-focusable
- // and not read-only
- if (options.focus === true)
- {
- // pick first element in form
- if (field.children && field.children.length > 0)
- {
- for (var z = 0; z < field.children.length; z++)
- {
- if (field.children[z].isControlField)
- {
- if (field.children[z].isAutoFocusable() && !field.children[z].options.readonly)
- {
- doFocus(field.children[z]);
- break;
- }
- }
- }
- }
- }
- else if (typeof(options.focus) === "string")
- {
- // assume it is a path to the child
- var child = field.getControlByPath(options.focus);
- if (child && child.isControlField && child.isAutoFocusable())
- {
- doFocus(child);
- }
- }
- }
-
- _resetInitValidationError(field);
- }
- }, 500);
- }
- else
- {
- _resetInitValidationError(field);
- }
-
- if (renderedCallback)
- {
- renderedCallback(field);
- }
- };
-
- loadAllConnector.loadAll({
- "data": data,
- "schema": schema,
- "options": options,
- "view": view,
- "dataSource": dataSource,
- "schemaSource": schemaSource,
- "optionsSource": optionsSource,
- "viewSource": viewSource
- }, function(loadedData, loadedOptions, loadedSchema, loadedView) {
-
- // for cases where things could not be loaded via source loaders, fall back to what may have been passed
- // in directly as values
-
- loadedData = loadedData ? loadedData : data;
- loadedSchema = loadedSchema ? loadedSchema: schema;
- loadedOptions = loadedOptions ? loadedOptions : options;
- loadedView = loadedView ? loadedView : view;
-
- // some defaults for the case where data is null
- // if schema + options are not provided, we assume a text field
-
- if (Alpaca.isEmpty(loadedData))
- {
- if (Alpaca.isEmpty(loadedSchema) && (Alpaca.isEmpty(loadedOptions) || Alpaca.isEmpty(loadedOptions.type)))
- {
- loadedData = "";
-
- if (Alpaca.isEmpty(loadedOptions))
- {
- loadedOptions = "text";
- }
- else if (options && Alpaca.isObject(options))
- {
- loadedOptions.type = "text";
- }
- }
- }
-
- if (loadedOptions.view)
- {
- loadedView = loadedOptions.view;
- }
-
- // init alpaca
- return Alpaca.init(el, loadedData, loadedOptions, loadedSchema, loadedView, initialSettings, callback, _renderedCallback, connector, errorCallback);
-
- }, function (loadError) {
- errorCallback(loadError);
- return null;
- });
- };
-
- /**
- * @namespace Namespace for all Alpaca Field Class Implementations.
- */
- Alpaca.Fields = { };
-
- /**
- * @namespace Namespace for all Alpaca Connector Class Implementations.
- */
- Alpaca.Connectors = { };
-
- Alpaca.Extend = $.extend;
-
- Alpaca.Create = function()
- {
- var args = Array.prototype.slice.call(arguments);
- args.unshift({});
-
- return $.extend.apply(this, args);
- };
-
- // static methods and properties
- Alpaca.Extend(Alpaca,
- /** @lends Alpaca */
- {
- /**
- * Makes an array.
- *
- * @param {Any} nonArray A non-array variable.
- * @returns {Array} Array out of the non-array variable.
- */
- makeArray : function(nonArray) {
- return Array.prototype.slice.call(nonArray);
- },
-
- /**
- * Finds whether the type of a variable is function.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a function, false otherwise.
- */
- isFunction: function(obj) {
- return Object.prototype.toString.call(obj) === "[object Function]";
- },
-
- /**
- * Finds whether the type of a variable is string.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a string, false otherwise.
- */
- isString: function(obj) {
- return (typeof obj === "string");
- },
-
- /**
- * Finds whether the type of a variable is object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an object, false otherwise.
- */
- isObject: function(obj) {
- return !Alpaca.isUndefined(obj) && Object.prototype.toString.call(obj) === '[object Object]';
- },
-
- /**
- * Finds whether the type of a variable is a plain, non-prototyped object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a plain object, false otherwise.
- */
- isPlainObject: function(obj) {
- return $.isPlainObject(obj);
- },
-
- /**
- * Finds whether the type of a variable is number.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a number, false otherwise.
- */
- isNumber: function(obj) {
- return (typeof obj === "number");
- },
-
- /**
- * Finds whether the type of a variable is array.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an array, false otherwise.
- */
- isArray: function(obj) {
- return obj instanceof Array;
- },
-
- /**
- * Finds whether the type of a variable is boolean.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a boolean, false otherwise.
- */
- isBoolean: function(obj) {
- return (typeof obj === "boolean");
- },
-
- /**
- * Finds whether the type of a variable is undefined.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a undefined, false otherwise.
- */
- isUndefined: function(obj) {
- return (typeof obj == "undefined");
- },
-
- /**
- * Strips any excess whitespace characters from the given text.
- * Returns the trimmed string.
- *
- * @param str
- *
- * @return trimmed string
- */
- trim: function(text)
- {
- var trimmed = text;
-
- if (trimmed && Alpaca.isString(trimmed))
- {
- trimmed = trimmed.replace(/^\s+|\s+$/g, '');
- }
-
- return trimmed;
- },
-
- /**
- * Provides a safe conversion of an HTML textual string into a DOM object.
- *
- * @param x
- * @return {*}
- */
- safeDomParse: function(x)
- {
- if (x && Alpaca.isString(x))
- {
- x = Alpaca.trim(x);
-
- // convert to dom
- var converted = null;
- try
- {
- converted = $(x);
- }
- catch (e)
- {
- // make another attempt to account for safety in some browsers
- x = "displayReadonly
attribute set to false, the read-only field will not appear.",
- "type": "boolean",
- "default": false
- },
- "required": {
- "title": "Required",
- "description": "Indicates whether the field's value is required. If set to true, the field must take on a valid value and cannnot be left empty or unassigned.",
- "type": "boolean",
- "default": false
- },
- "default": {
- "title": "Default",
- "description": "The default value to be assigned for this property. If the data for the field is empty or not provided, this default value will be plugged in for you. Specify a default value when you want to pre-populate the field's value ahead of time.",
- "type": "any"
- },
- "type": {
- "title": "Type",
- "description": "Data type of the property.",
- "type": "string",
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Data format of the property.",
- "type": "string"
- },
- "disallow": {
- "title": "Disallowed Values",
- "description": "List of disallowed values for the property.",
- "type": "array"
- },
- "dependencies": {
- "title": "Dependencies",
- "description": "List of property dependencies.",
- "type": "array"
- }
- }
- };
- if (this.getType && !Alpaca.isValEmpty(this.getType())) {
- schemaOfSchema.properties.type['default'] = this.getType();
- schemaOfSchema.properties.type['enum'] = [this.getType()];
- }
- return schemaOfSchema;
- },
-
- /**
- * Returns Alpaca options for the schema properties that managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the schema properties that are managed by this class.
- */
- getOptionsForSchema: function() {
- return {
- "fields": {
- "title": {
- "helper": "Field short description",
- "type": "text"
- },
- "description": {
- "helper": "Field detailed description",
- "type": "textarea"
- },
- "readonly": {
- "helper": "Field will be read only if checked",
- "rightLabel": "This field is read-only",
- "type": "checkbox"
- },
- "required": {
- "helper": "Field value must be set if checked",
- "rightLabel": "This field is required",
- "type": "checkbox"
- },
- "default": {
- "helper": "Field default value",
- "type": "textarea"
- },
- "type": {
- "helper": "Field data type",
- "type": "text"
- },
- "format": {
- "type": "select",
- "dataSource": function(callback) {
- for (var key in Alpaca.defaultFormatFieldMapping)
- {
- this.selectOptions.push({
- "value": key,
- "text": key
- });
- }
-
- callback();
- }
- },
- "disallow": {
- "helper": "Disallowed values for the field",
- "itemLabel":"Value",
- "type": "array"
- },
- "dependencies": {
- "helper": "Field Dependencies",
- "multiple":true,
- "size":3,
- "type": "select",
- "dataSource": function (field, callback) {
- if (field.parent && field.parent.schemaParent && field.parent.schemaParent.parent) {
- for (var key in field.parent.schemaParent.parent.childrenByPropertyId) {
- if (key != field.parent.schemaParent.propertyId) { // jshint ignore:line
- field.selectOptions.push({
- "value": key,
- "text": key
- });
- }
- }
- }
- if (callback) {
- callback();
- }
- }
- }
- }
- };
- },
-
- /**
- * Returns JSON schema of the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} JSON schema of the Alpaca options that are managed by this class.
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = {
- "title": "Options for " + this.getTitle(),
- "description": this.getDescription() + " (Options)",
- "type": "object",
- "properties": {
- "form":{},
- "id": {
- "title": "Field Id",
- "description": "Unique field id. Auto-generated if not provided.",
- "type": "string"
- },
- "type": {
- "title": "Field Type",
- "description": "Field type.",
- "type": "string",
- "default": this.getFieldType(),
- "readonly": true
- },
- "validate": {
- "title": "Validation",
- "description": "Field validation is required if true.",
- "type": "boolean",
- "default": true
- },
- "showMessages": {
- "title": "Show Messages",
- "description": "Display validation messages if true.",
- "type": "boolean",
- "default": true
- },
- "disabled": {
- "title": "Disabled",
- "description": "Field will be disabled if true.",
- "type": "boolean",
- "default": false
- },
- "readonly": {
- "title": "Readonly",
- "description": "Field will be readonly if true.",
- "type": "boolean",
- "default": false
- },
- "hidden": {
- "title": "Hidden",
- "description": "Field will be hidden if true.",
- "type": "boolean",
- "default": false
- },
- "label": {
- "title": "Label",
- "description": "Field label.",
- "type": "string"
- },
- "helper": {
- "title": "Helper",
- "description": "Field help message.",
- "type": "string"
- },
- "fieldClass": {
- "title": "CSS class",
- "description": "Specifies one or more CSS classes that should be applied to the dom element for this field once it is rendered. Supports a single value, comma-delimited values, space-delimited values or values passed in as an array.",
- "type": "string"
- },
- "hideInitValidationError" : {
- "title": "Hide Initial Validation Errors",
- "description" : "Hide initial validation errors if true.",
- "type": "boolean",
- "default": false
- },
- "focus": {
- "title": "Focus",
- "description": "If true, the initial focus for the form will be set to the first child element (usually the first field in the form). If a field name or path is provided, then the specified child field will receive focus. For example, you might set focus to 'name' (selecting the 'name' field) or you might set it to 'client/name' which picks the 'name' field on the 'client' object.",
- "type": "checkbox",
- "default": true
- },
- "optionLabels": {
- "title": "Enumerated Value Labels",
- "description": "An array of string labels for items in the enum array",
- "type": "array"
- },
- "view": {
- "title": "Override of the view for this field",
- "description": "Allows for this field to be rendered with a different view (such as 'display' or 'create')",
- "type": "string"
- }
- }
- };
- if (this.isTopLevel()) {
-
- schemaOfOptions.properties.form = {
- "title": "Form",
- "description": "Options for rendering the FORM tag.",
- "type": "object",
- "properties": {
- "attributes": {
- "title": "Form Attributes",
- "description": "List of attributes for the FORM tag.",
- "type": "object",
- "properties": {
- "id": {
- "title": "Id",
- "description": "Unique form id. Auto-generated if not provided.",
- "type": "string"
- },
- "action": {
- "title": "Action",
- "description": "Form submission endpoint",
- "type": "string"
- },
- "method": {
- "title": "Method",
- "description": "Form submission method",
- "enum":["post","get"],
- "type": "string"
- },
- "rubyrails": {
- "title": "Ruby On Rails",
- "description": "Ruby on Rails Name Standard",
- "enum": ["true", "false"],
- "type": "string"
- },
- "name": {
- "title": "Name",
- "description": "Form name",
- "type": "string"
- },
- "focus": {
- "title": "Focus",
- "description": "Focus Setting",
- "type": "any"
- }
- }
- },
- "buttons": {
- "title": "Form Buttons",
- "description": "Configuration for form-bound buttons",
- "type": "object",
- "properties": {
- "submit": {
- "type": "object",
- "title": "Submit Button",
- "required": false
- },
- "reset": {
- "type": "object",
- "title": "Reset button",
- "required": false
- }
- }
- },
- "toggleSubmitValidState": {
- "title": "Toggle Submit Valid State",
- "description": "Toggle the validity state of the Submit button",
- "type": "boolean",
- "default": true
- }
- }
- };
-
- } else {
- delete schemaOfOptions.properties.form;
- }
-
- return schemaOfOptions;
- },
-
- /**
- * Returns Alpaca options for the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the Alpaca options that are managed by this class.
- */
- getOptionsForOptions: function() {
- var optionsForOptions = {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "type": {
- "type": "text"
- },
- "validate": {
- "rightLabel": "Enforce validation",
- "type": "checkbox"
- },
- "showMessages": {
- "rightLabel":"Show validation messages",
- "type": "checkbox"
- },
- "disabled": {
- "rightLabel":"Disable this field",
- "type": "checkbox"
- },
- "hidden": {
- "type": "checkbox",
- "rightLabel": "Hide this field"
- },
- "label": {
- "type": "text"
- },
- "helper": {
- "type": "textarea"
- },
- "fieldClass": {
- "type": "text"
- },
- "hideInitValidationError": {
- "rightLabel": "Hide initial validation errors",
- "type": "checkbox"
- },
- "focus": {
- "type": "checkbox",
- "rightLabel": "Auto-focus first child field"
- },
- "optionLabels": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "view": {
- "type": "text"
- }
- }
- };
- if (this.isTopLevel()) {
- optionsForOptions.fields.form = {
- "type": "object",
- "fields": {
- "attributes": {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "action": {
- "type": "text"
- },
- "method": {
- "type": "select"
- },
- "name": {
- "type": "text"
- }
- }
- }
- }
- };
- }
-
- return optionsForOptions;
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "disallowValue": "{0} are disallowed values.",
- "notOptional": "This field is not optional."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ControlField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ControlField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a control field.
- */
- onConstruct: function()
- {
- var _this = this;
-
- this.isControlField = true;
-
- // helper method for getting val() from the control
- // handles conversion to the correct scalar type
- this._getControlVal = function(ensureProperType) {
- var val = null;
-
- if (this.control)
- {
- val = $(this.control).val();
-
- if (ensureProperType)
- {
- val = _this.ensureProperType(val);
- }
- }
-
- return val;
- };
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var controlTemplateType = self.resolveControlTemplateType();
- if (!controlTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for control: " + self.getFieldType());
- }
-
- this.controlDescriptor = this.view.getTemplateDescriptor("control-" + controlTemplateType, self);
- },
-
- getControlEl: function()
- {
- return this.control;
- },
-
- resolveControlTemplateType: function()
- {
- var self = this;
-
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("control-" + b.getFieldType(), self);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- onSetup: function()
- {
-
- },
-
- isAutoFocusable: function()
- {
- return true;
- },
-
- /**
- * For control fields, we use the "control" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "control";
- },
-
- /**
- * Add a "control" dom element inside of the field which houses our custom control.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.control = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTROL_FIELD);
- this.control.removeClass(Alpaca.MARKER_CLASS_CONTROL_FIELD);
-
- // render
- self.prepareControlModel(function(model) {
- self.beforeRenderControl(model, function() {
- self.renderControl(model, function(controlField) {
-
- if (controlField)
- {
- self.control.replaceWith(controlField);
- self.control = controlField;
-
- self.control.addClass(Alpaca.CLASS_CONTROL);
- }
-
- // CALLBACK: "control"
- self.fireCallback("control");
-
- self.afterRenderControl(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the control.
- *
- * @param callback function(model)
- */
- prepareControlModel: function(callback)
- {
- var self = this;
-
- var model = {};
- model.id = this.getId();
- model.name = this.name;
- model.options = this.options;
- model.schema = this.schema;
- model.data = this.data;
- model.required = this.isRequired();
- model.view = this.view;
-
- callback(model);
- },
-
- /**
- * Called before the control is rendered.
- *
- * @extension-point
- *
- * @param callback
- */
- beforeRenderControl: function(model, callback)
- {
- callback();
- },
-
- /**
- * Called after the control is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- if (!self.firstUpdateObservableFire)
- {
- if ((typeof(self.data) == "undefined") || self.data == null)
- {
- // do not handle
- }
- else
- {
- self.firstUpdateObservableFire = true;
- self.updateObservable();
- }
- }
-
- callback();
- },
-
- /**
- * Renders the control into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderControl: function(model, callback)
- {
- var control = null;
-
- if (this.controlDescriptor)
- {
- control = Alpaca.tmpl(this.controlDescriptor, model);
- }
-
- callback(control);
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- /*
- // store reference to the label
- this.labelDiv = $(this.field).find(".alpaca-controlfield-label");
- var labelDiv = $('.alpaca-controlfield-label', this.outerEl);
- if (labelDiv.length) {
- this.labelDiv = labelDiv;
- }
-
- var helperDiv = $('.alpaca-controlfield-helper', this.outerEl);
- if (helperDiv.length) {
- this.helperDiv = helperDiv;
- }
- */
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#setDefault
- */
- setDefault: function() {
- var defaultData = Alpaca.isEmpty(this.schema['default']) ? "" : this.schema['default'];
- this.setValue(defaultData);
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- if (this.schema["enum"]) {
- var val = this.data;
- val = this.getValue();
- /*this.getValue();*/
- if (!this.isRequired() && Alpaca.isValEmpty(val)) {
- return true;
- }
- if ($.inArray(val, this.schema["enum"]) > -1) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateEnum();
- valInfo["invalidValueOfEnum"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidValueOfEnum"), [this.schema["enum"].join(', '), this.data]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidValueOfEnum"]["status"];
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- this.initControlEvents();
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- var control = this.control;
-
- control.click(function(e) {
- self.onClick.call(self, e);
- self.trigger("click", e);
- });
-
- // trigger control level handlers for things that happen to input element
- control.change(function(e) {
-
- // we use a timeout here because we want this to run AFTER control click handlers
- setTimeout(function() {
- self.onChange.call(self, e);
- self.triggerWithPropagation("change", e);
- }, 250);
- });
-
- control.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- control.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
-
- control.keypress(function(e) {
- self.onKeyPress.call(self, e);
- self.trigger("keypress", e);
- });
-
- control.keyup(function(e) {
- self.onKeyUp.call(self, e);
- self.trigger("keyup", e);
- });
-
- control.keydown(function(e) {
- self.onKeyDown.call(self, e);
- self.trigger("keydown", e);
- });
- },
-
- /**
- * Callback for when a key press event is received for the field control.
- *
- * @param {Object} e keypress event
- */
- onKeyPress: function(e)
- {
- var self = this;
-
- // if the field is currently invalid, then we provide early feedback to the user as to when they enter
- // if the field was valid, we don't render invalidation feedback until they blur the field
-
- // was the control valid previously?
- var wasValid = this.isValid();
- if (!wasValid)
- {
- //
- // we use a timeout because at this exact moment, the value of the control is still the old value
- // jQuery raises the keypress event ahead of the input receiving the new data which would incorporate
- // the key that was pressed
- //
- // this timeout provides the browser with enough time to plug the value into the input control
- // which the validation logic uses to determine whether the control is now in a valid state
- //
- window.setTimeout(function() {
- self.refreshValidationState();
- }, 50);
- }
-
- },
-
- /**
- * Callback for when a key down event is received for the field control.
- *
- * @param {Object} e keydown event
- */
- onKeyDown: function(e)
- {
- },
-
- /**
- * Callback for when a key up event is received for the field control.
- *
- * @param {Object} e keyup event
- */
- onKeyUp: function(e)
- {
- },
-
- /**
- * Handler for click event.
- *
- * @param {Object} e Click event.
- */
- onClick: function(e)
- {
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", true);
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", false);
- }
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumerated Values",
- "description": "List of specific values for this property",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "enum": {
- "itemLabel":"Value",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "name": {
- "title": "Field Name",
- "description": "Field Name.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "name": {
- "type": "text"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "invalidValueOfEnum": "This field should have one of the values in {0}. Current value is: {1}"
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ContainerField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ContainerField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a container field.
- */
- onConstruct: function()
- {
- this.isContainerField = true;
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return true;
- },
-
- getContainerEl: function()
- {
- return this.container;
- },
-
- /**
- * For container fields, we use the "container" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "container";
- },
-
- resolveContainerTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType(), this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- resolveContainerItemTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType() + "-item", this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerTemplateType = self.resolveContainerTemplateType();
- if (!containerTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container: " + self.getFieldType());
- }
-
- this.containerDescriptor = this.view.getTemplateDescriptor("container-" + containerTemplateType, self);
-
- var collapsible = true;
-
- if (!Alpaca.isEmpty(this.view.collapsible)) {
- collapsible = this.view.collapsible;
- }
-
- if (!Alpaca.isEmpty(this.options.collapsible)) {
- collapsible = this.options.collapsible;
- }
-
- this.options.collapsible = collapsible;
-
- var legendStyle = "button";
-
- if (!Alpaca.isEmpty(this.view.legendStyle)) {
- legendStyle = this.view.legendStyle;
- }
-
- if (!Alpaca.isEmpty(this.options.legendStyle)) {
- legendStyle = this.options.legendStyle;
- }
-
- this.options.legendStyle = legendStyle;
-
- //Lazy loading
- this.lazyLoading = false;
- if (!Alpaca.isEmpty(this.options.lazyLoading)) {
- this.lazyLoading = this.options.lazyLoading;
- if (this.lazyLoading) {
- this.options.collapsed = true;
- }
- //delete this.options.lazyLoading;
- }
- // holders of references to children
- this.children = [];
- this.childrenById = {};
- this.childrenByPropertyId = {};
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // if this container is DOM-wrapped with a form, then release the form
- if (this.form)
- {
- this.form.destroy(true); // pass in true so that we don't call back recursively
- delete this.form;
- }
-
- // destroy any child controls
- Alpaca.each(this.children, function() {
- this.destroy();
- });
-
- // call up to base method
- this.base();
- },
-
- /**
- * Add a "container" dom element inside of the field which houses our custom container.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.container = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD);
- this.container.removeClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD);
-
- // render
- self.prepareContainerModel(function(model) {
- self.beforeRenderContainer(model, function() {
- self.renderContainer(model, function(containerField) {
-
- if (containerField)
- {
- self.container.replaceWith(containerField);
- self.container = containerField;
-
- self.container.addClass(Alpaca.CLASS_CONTAINER);
- }
-
- // mark the form field with "alpaca-horizontal" or "alpaca-vertical"
- if (self.view.horizontal)
- {
- self.container.addClass("alpaca-horizontal");
- }
- else
- {
- self.container.addClass("alpaca-vertical");
- }
-
- // CALLBACK: "container"
- self.fireCallback("container");
-
- self.afterRenderContainer(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the container.
- *
- * @param callback function(model)
- */
- prepareContainerModel: function(callback)
- {
- var self = this;
-
- var model = {
- "id": this.getId(),
- "name": this.name,
- "schema": this.schema,
- "options": this.options,
- "view": this.view
- };
-
- // load items into array and store on model for future use
- self.createItems(function(items) {
-
- if (!items)
- {
- items = [];
- }
-
- // legacy support: assume containerItemEl = fieldEl
- for (var i = 0; i < items.length; i++)
- {
- if (!items[i].containerItemEl) {
- items[i].containerItemEl = items[i].getFieldEl();
- }
- }
-
- model.items = items;
-
- callback(model);
-
- });
- },
-
- /**
- * Called before the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- beforeRenderContainer: function(model, callback)
- {
- var self = this;
-
- callback();
- },
-
- /**
- * Renders the container into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderContainer: function(model, callback)
- {
- var container = null;
-
- if (this.containerDescriptor)
- {
- container = Alpaca.tmpl(this.containerDescriptor, model);
- }
-
- callback(container);
- },
-
- /**
- * Called after the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- self.beforeApplyCreatedItems(model, function() {
- self.applyCreatedItems(model, function () {
- self.afterApplyCreatedItems(model, function () {
- callback();
- });
- });
- });
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- var self = this;
-
- this.base();
-
- /*
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
- */
- },
-
- /**
- * Creates any sub-items for this container.
- *
- * @extension_point
- *
- * @param callback
- */
- createItems: function(callback)
- {
- callback();
- },
-
- beforeApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.isTopLevel() && self.view.getLayout())
- {
- layoutBindings = self.view.getLayout().bindings;
-
- // if layout and bindings not provided, assume a default strategy
- if (!layoutBindings && self.view.getLayout().templateDescriptor && model.items.length > 0)
- {
- layoutBindings = {};
-
- for (var i = 0; i < model.items.length; i++)
- {
- var name = model.items[i].name;
-
- layoutBindings[name] = "[data-alpaca-layout-binding='" + name + "']";
- }
- }
-
- }
-
- if (model.items.length > 0)
- {
- $(self.container).addClass("alpaca-container-has-items");
- $(self.container).attr("data-alpaca-container-item-count", model.items.length);
- }
- else
- {
- $(self.container).removeClass("alpaca-container-has-items");
- $(self.container).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < model.items.length; i++)
- {
- var item = model.items[i];
-
- // find the insertion point
- var insertionPoint = $(self.container).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM + "[" + Alpaca.MARKER_DATA_CONTAINER_FIELD_ITEM_KEY + "='" + item.name + "']");
- if (!layoutBindings)
- {
- var holder = $(insertionPoint).parent();
-
- $(insertionPoint).replaceWith(item.containerItemEl);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- else
- {
- // use a layout
- var bindingId = layoutBindings[item.name];
- if (bindingId)
- {
- var holder = $(bindingId, self.field);
- if (holder.length == 0)
- {
- // legacy support, fallback to ID based
- try {
- holder = $('#' + bindingId, self.field);
- } catch (e) { }
- }
- if (holder.length > 0)
- {
- $(item.containerItemEl).appendTo(holder);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- }
-
- // remove insertion point
- $(insertionPoint).remove();
- }
-
- $(item.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-first");
- }
-
- if (i + 1 === model.items.length)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(item.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(item.containerItemEl).attr("data-alpaca-container-item-name", item.name);
- $(item.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
-
- // register the child
- self.registerChild(item, i);
- }
-
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
-
- self.triggerUpdate();
- callback();
- },
-
- afterApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- /**
- * Helper method to add child field.
- *
- * @param {Alpaca.Control} child Child field to be added.
- * @param {Integer} index Index of the new child.
- */
- registerChild: function(child, index)
- {
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 0, child);
- }
- else
- {
- this.children.push(child);
- }
-
- this.childrenById[child.getId()] = child;
- if (child.propertyId)
- {
- this.childrenByPropertyId[child.propertyId] = child;
- }
-
- child.parent = this;
- },
-
- /**
- * Helper method to remove child field.
- *
- * @param index
- */
- unregisterChild: function(index)
- {
- var child = this.children[index];
- if (!child)
- {
- return;
- }
-
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 1);
- }
-
- delete this.childrenById[child.getId()];
- if (child.propertyId)
- {
- delete this.childrenByPropertyId[child.propertyId];
- }
-
- child.parent = null;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updateChildDOMElements: function()
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.view.getLayout()) {
- layoutBindings = self.view.getLayout().bindings;
- }
-
- if (!layoutBindings)
- {
- if (self.children.length > 0)
- {
- $(self.getContainerEl()).addClass("alpaca-container-has-items");
- $(self.getContainerEl()).attr("data-alpaca-container-item-count", self.children.length);
- }
- else
- {
- $(self.getContainerEl()).removeClass("alpaca-container-has-items");
- $(self.getContainerEl()).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < self.children.length; i++)
- {
- var child = self.children[i];
-
- // reset path and name
- child.path = self.path + "[" + i + "]";
- child.calculateName();
-
- $(child.containerItemEl).removeClass("alpaca-container-item-first");
- $(child.containerItemEl).removeClass("alpaca-container-item-last");
- $(child.containerItemEl).removeClass("alpaca-container-item-index");
- $(child.containerItemEl).removeClass("alpaca-container-item-key");
-
- $(child.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-first");
- }
- if (i + 1 === self.children.length)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(child.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(child.containerItemEl).attr("data-alpaca-container-item-name", child.name);
- $(child.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
- }
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentReveal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentReveal();
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentConceal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentConceal();
- }
- },
-
- /**
- * Focus an element in the container. Find the first invalid element or if no invalid elements, pick
- * the first child.
- */
- focus: function()
- {
- this.base();
-
- var index = -1;
-
- for (var i = 0; i < this.children.length; i++)
- {
- if (!this.children[i].isValid(true))
- {
- index = i;
- break;
- }
- }
- if (index === -1 && this.children.length > 0)
- {
- index = 0;
- }
-
- if (index > -1)
- {
- this.children[index].focus();
- }
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].disable();
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].enable();
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "lazyLoading": {
- "title": "Lazy Loading",
- "description": "Child fields will only be rendered when the fieldset is expanded if this option is set true.",
- "type": "boolean",
- "default": false
- },
- "collapsible": {
- "title": "Collapsible",
- "description": "Field set is collapsible if true.",
- "type": "boolean",
- "default": true
- },
- "collapsed": {
- "title": "Collapsed",
- "description": "Field set is initially collapsed if true.",
- "type": "boolean",
- "default": false
- },
- "legendStyle": {
- "title": "Legend Style",
- "description": "Field set legend style.",
- "type": "string",
- "enum":["button","link"],
- "default": "button"
- },
- "animate": {
- "title": "Animate movements and transitions",
- "description": "Up and down transitions will be animated",
- "type": "boolean",
- "default": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "lazyLoading": {
- "rightLabel": "Lazy loading child fields ?",
- "helper": "Lazy loading will be enabled if checked.",
- "type": "checkbox"
- },
- "collapsible": {
- "rightLabel": "Field set collapsible ?",
- "helper": "Field set is collapsible if checked.",
- "type": "checkbox"
- },
- "collapsed": {
- "rightLabel": "Field set initially collapsed ?",
- "description": "Field set is initially collapsed if checked.",
- "type": "checkbox"
- },
- "legendStyle": {
- "type":"select"
- },
- "animate": {
- "rightLabel": "Animate movements and transitions",
- "type": "checkbox"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Connector = Base.extend(
- /**
- * @lends Alpaca.Connector.prototype
- */
- {
- /**
- * @constructs
- * @class Connects Alpaca to remote data stores.
-
- * @param {String} id Connector ID.
- */
- constructor: function(id)
- {
- this.id = id;
-
- // helper function to determine if a resource is a uri
- this.isUri = function(resource)
- {
- return !Alpaca.isEmpty(resource) && Alpaca.isUri(resource);
- };
-
- var ONE_HOUR = 3600000;
- this.cache = new AjaxCache('URL', true, ONE_HOUR);
- },
-
- /**
- * Makes initial connections to data source.
- *
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- connect: function (onSuccess, onError)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess();
- }
- },
-
- /**
- * Loads a template (HTML or Text).
- *
- * If the source is a URI, then it is loaded.
- * If it is not a URI, then the source is simply handed back.
- *
- * @param {Object|String} source Source to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadTemplate : function (source, onSuccess, onError)
- {
- if (!Alpaca.isEmpty(source))
- {
- if (Alpaca.isUri(source))
- {
- this.loadUri(source, false, function(loadedData) {
-
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loadedData);
- }
-
- }, function (loadError) {
-
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- });
- }
- else
- {
- onSuccess(source);
- }
- }
- else
- {
- onError({
- "message":"Empty data source.",
- "reason": "TEMPLATE_LOADING_ERROR"
- });
- }
- },
-
- /**
- * Loads JSON data.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback
- * @param {Function} onError onError callback
- */
- loadData: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON view.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadView: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads schema, form, view and data in a single call.
- *
- * @param {Object} resources resources
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadAll: function (resources, onSuccess, onError)
- {
- var dataSource = resources.dataSource;
- var schemaSource = resources.schemaSource;
- var optionsSource = resources.optionsSource;
- var viewSource = resources.viewSource;
-
- // we allow "schema" to contain a URI as well (backwards-compatibility)
- if (!schemaSource)
- {
- schemaSource = resources.schema;
- }
-
- // we allow "options" to contain a URI as well (backwards-compatibility)
- if (!optionsSource)
- {
- optionsSource = resources.options;
- }
-
- // we allow "view" to contain a URI as well (backwards-compatibility)
- if (!viewSource)
- {
- viewSource = resources.view;
- }
-
- var loaded = {};
-
- var loadCounter = 0;
- var invocationCount = 0;
-
- var successCallback = function()
- {
- if (loadCounter === invocationCount)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loaded.data, loaded.options, loaded.schema, loaded.view);
- }
- }
- };
-
- var errorCallback = function (loadError)
- {
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- };
-
- // count out the total # of invokes we're going to fire off
- if (dataSource)
- {
- invocationCount++;
- }
- if (schemaSource)
- {
- invocationCount++;
- }
- if (optionsSource)
- {
- invocationCount++;
- }
- if (viewSource)
- {
- invocationCount++;
- }
- if (invocationCount === 0)
- {
- // nothing to invoke, so just hand back
- successCallback();
- return;
- }
-
- // fire off all of the invokes
- if (dataSource)
- {
- this.loadData(dataSource, function(data) {
- loaded.data = data;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (schemaSource)
- {
- this.loadSchema(schemaSource, function(schema) {
- loaded.schema = schema;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (optionsSource)
- {
- this.loadOptions(optionsSource, function(options) {
- loaded.options = options;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (viewSource)
- {
- this.loadView(viewSource, function(view) {
- loaded.view = view;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- },
-
- /**
- * Loads a JSON through Ajax call.
- *
- * @param {String} uri location of the json document
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadJson : function(uri, onSuccess, onError) {
- this.loadUri(uri, true, onSuccess, onError);
- } ,
-
- /**
- * Loads a general document through Ajax call.
- *
- * This uses jQuery to perform the Ajax call. If you need to customize connectivity to your own remote server,
- * this would be the appropriate place to do so.
- *
- * @param {String} uri uri to be loaded
- * @param {Boolean} isJson Whether the document is a JSON or not.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadUri : function(uri, isJson, onSuccess, onError) {
-
- var self = this;
-
- var ajaxConfigs = {
- "url": uri,
- "type": "get",
- "success": function(jsonDocument) {
-
- self.cache.put(uri, jsonDocument);
-
- if (onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(jsonDocument);
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
- if (onError && Alpaca.isFunction(onError)) {
- onError({
- "message":"Unable to load data from uri : " + uri,
- "stage": "DATA_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- }
- };
-
- if (isJson) {
- ajaxConfigs.dataType = "json";
- } else {
- ajaxConfigs.dataType = "text";
- }
-
- var cachedDocument = self.cache.get(uri);
-
- if (cachedDocument !== false && onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(cachedDocument);
- } else {
- $.ajax(ajaxConfigs);
- }
- },
-
- /**
- * Loads referenced JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads referenced JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- _handleLoadJsonResource: function (resource, successCallback, errorCallback)
- {
- if (this.isUri(resource))
- {
- this.loadJson(resource, function(loadedResource) {
- successCallback(loadedResource);
- }, errorCallback);
- }
- else
- {
- successCallback(resource);
- }
- }
-
- });
-
- Alpaca.registerConnectorClass("default", Alpaca.Connector);
-
-
-
-
-
-
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // AJAX CACHE
- //
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
- /*!
- * ajax-cache JavaScript Library v0.2.1
- * http://code.google.com/p/ajax-cache/
- *
- * Includes few JSON methods (open source)
- * http://www.json.org/js.html
- *
- * Date: 2010-08-03
- */
- var AjaxCache = function AjaxCache(type, on, lifetime) {
- if (on) {
- this.on = true;
- } else {
- this.on = false;
- }
-
- // set default cache lifetime
- if (lifetime != null) {
- this.defaultLifetime = lifetime;
- }
-
- // set type
- this.type = type;
-
- // set cache functions according to type
- switch (this.type) {
- case 'URL':
- this.put = this.put_url;
- break;
- case 'GET':
- this.put = this.put_GET;
- break;
- }
-
- };
-
- AjaxCache.prototype.on = false;
- AjaxCache.prototype.type = undefined;
- AjaxCache.prototype.defaultLifetime = 1800000; // 1800000=30min, 300000=5min, 30000=30sec
- AjaxCache.prototype.items = {};
-
- /**
- * Caches the request and its response. Type: url
- *
- * @param url - url of ajax response
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_url = function(url, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Caches the request and its response. Type: GET
- *
- * @param url - url of ajax response
- * @param data - data params (query)
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_GET = function(url, data, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url, [ data ]);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].data = data;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Get cached ajax response
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return ajax response or false if such does not exist or is expired
- */
- AjaxCache.prototype.get = function(url, params) {
- var key = this.make_key(url, params);
-
- // if cache does not exist
- if (this.items[key] == null) {
- return false;
- }
-
- // if cache expired
- if (this.items[key].expire < (new Date().getTime())) {
- return false;
- }
-
- // everything is passed - lets return the response
- return this.items[key].response;
- };
-
- /**
- * Make unique key for each request depending on url and additional parameters
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return unique key
- */
- AjaxCache.prototype.make_key = function(url, params) {
- var key = url;
- switch (this.type) {
- case 'URL':
- break;
- case 'GET':
- key += this.stringify(params[0]);
- break;
- }
-
- return key;
- };
-
- /**
- * Flush cache
- *
- * @return true on success
- */
- AjaxCache.prototype.flush = function() {
- // flush all cache
- cache.items = {};
- return true;
- };
-
- /*
- * Methods to stringify JavaScript/JSON objects.
- *
- * Taken from: http://www.json.org/js.html to be more exact, this file:
- * http://www.json.org/json2.js copied on 2010-07-19
- *
- * Taken methods: stringify, quote and str
- *
- * Methods are slightly modified to best fit ajax-cache functionality
- *
- */
- AjaxCache.prototype.stringify = function(value, replacer, space) {
-
- // The stringify method takes a value and an optional replacer, and an
- // optional
- // space parameter, and returns a JSON text. The replacer can be a function
- // that can replace values, or an array of strings that will select the
- // keys.
- // A default replacer method can be provided. Use of the space parameter can
- // produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
- // If the space parameter is a number, make an indent string containing that
- // many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
- // If the space parameter is a string, it will be used as the indent
- // string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
- // If there is a replacer, it must be a function or an array.
- // Otherwise, throw an error.
-
- rep = replacer;
- if (replacer &&
- typeof replacer !== 'function' &&
- (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
- // Make a fake root object containing our value under the key of ''.
- // Return the result of stringifying the value.
-
- return this.str('', {
- '' : value
- });
- };
-
- AjaxCache.prototype.quote = function(string) {
-
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe escape
- // sequences.
-
- var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable,
- function(a) {
- var c = meta[a];
- return typeof c === 'string' ? c : '\\u' + ('0000' + a
- .charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- };
-
- AjaxCache.prototype.str = function(key, holder) {
-
- // Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length, mind = gap, partial, value = holder[key];
-
- // If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value &&
- typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
- // If we were called with a replacer function, then call the replacer to
- // obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
- // What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return this.quote(value);
-
- case 'number':
-
- // JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
- // If the value is a boolean or null, convert it to a string. Note:
- // typeof null does not produce 'null'. The case is included here in
- // the remote chance that this gets fixed someday.
-
- return String(value);
-
- // If the type is 'object', we might be dealing with an object or an
- // array or
- // null.
-
- case 'object':
-
- // Due to a specification blunder in ECMAScript, typeof null is
- // 'object',
- // so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
- // Make an array to hold the partial results of stringifying this object
- // value.
-
- gap += indent;
- partial = [];
-
- // Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
- // The value is an array. Stringify every element. Use null as a
- // placeholder
- // for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = this.str(i, value) || 'null';
- }
-
- // Join all of the elements together, separated with commas, and
- // wrap them in
- // brackets.
-
- v = partial.length === 0 ? '[]' : gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
- // If the replacer is an array, use it to select the members to be
- // stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
- // Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
- // Join all of the member texts together, separated with commas,
- // and wrap them in braces.
-
- v = partial.length === 0 ?
- '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- };
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Form = Base.extend(
- /**
- * @lends Alpaca.Form.prototype
- */
- {
- /**
- * @constructs
- *
- * @class This class is for managing HTML form control.
- *
- * @param {Object} container Field container.
- * @param {Object} options Field options.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(domEl, options, viewId, connector, errorCallback) {
-
- // container
- this.domEl = domEl;
-
- // parent
- this.parent = null;
-
- this.connector = connector;
- this.errorCallback = errorCallback;
-
- // options
- this.options = options;
-
- if (this.options.attributes)
- {
- this.attributes = this.options.attributes;
- }
- else
- {
- this.attributes = {};
- }
-
- if (this.options.buttons)
- {
- if (this.options.buttons.submit)
- {
- if (!this.options.buttons.submit.type)
- {
- this.options.buttons.submit.type = 'submit';
- }
-
- if (!this.options.buttons.submit.name)
- {
- this.options.buttons.submit.name = 'submit';
- }
-
- if (!this.options.buttons.submit.value)
- {
- this.options.buttons.submit.value = 'Submit';
- }
- }
-
- if (this.options.buttons.reset)
- {
- if (!this.options.buttons.reset.type)
- {
- this.options.buttons.reset.type = 'reset';
- }
- if (!this.options.buttons.reset.name)
- {
- this.options.buttons.reset.name = 'reset';
- }
- if (!this.options.buttons.reset.value)
- {
- this.options.buttons.reset.value = 'Reset';
- }
- }
-
- // some general correction
- for (var k in this.options.buttons)
- {
- if (this.options.buttons[k].label)
- {
- this.options.buttons[k].value = this.options.buttons[k].label;
- }
- if (this.options.buttons[k].title)
- {
- this.options.buttons[k].value = this.options.buttons[k].title;
- }
- if (!this.options.buttons[k].type)
- {
- this.options.buttons[k].type = "button";
- }
- }
- }
-
- if (this.attributes.id)
- {
- this.id = this.attributes.id;
- }
- else
- {
- this.id = Alpaca.generateId();
- this.attributes.id = this.id;
- }
-
- // if we have a submit button specified, and toggleSubmitValidState isn't defined, set to true by default
- // don't allow the form to submit unless valid
- if (this.options.buttons && this.options.buttons.submit && Alpaca.isUndefined(this.options.toggleSubmitValidState))
- {
- this.options.toggleSubmitValidState = true;
- }
-
- this.viewType = options.viewType;
-
- // set a runtime view
- this.view = new Alpaca.RuntimeView(viewId, this);
- },
-
- /**
- * Renders this form into the container.
- *
- * @param {Function} callback
- */
- render: function(callback)
- {
- var self = this;
-
- // remove the previous form element if it exists
- if (this.form)
- {
- this.form.remove();
- }
-
- // load the appropriate template and render it
- this.processRender(this.domEl, function() {
-
- // bind our field dom element into the container
- self.form.appendTo(self.container);
-
- // add default class
- self.form.addClass("alpaca-form");
-
- // CALLBACK: "form"
- self.fireCallback("form");
-
- // execute callback
- callback(self);
- });
- },
-
- /**
- * Determines whether the top control is entirely valid.
- *
- * @return {*}
- */
- isFormValid: function()
- {
- // re-compute validation for the full control set
- this.topControl.validate(true);
-
- var valid = this.topControl.isValid(true);
- //this.refreshValidationState(true);
-
- return valid;
- },
-
- isValid: function()
- {
- return this.isFormValid();
- },
-
- validate: function(children)
- {
- return this.topControl.validate(children);
- },
-
- enableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", false);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- disableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", true);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- adjustSubmitButtonState: function()
- {
- this.disableSubmitButton();
-
- if (this.isFormValid())
- {
- this.enableSubmitButton();
- }
- },
-
- /**
- * Responsible for fetching any templates needed so as to render the
- * current mode for this field.
- *
- * Once completed, the onSuccess method is called.
- *
- * @param {Object} parentEl Field container.
- * @param {Function} callback
- */
- processRender: function(parentEl, callback)
- {
- var self = this;
-
- // lookup the template we should use to render
- this.formDescriptor = this.view.getTemplateDescriptor("form");
- if (!this.formDescriptor)
- {
- return Alpaca.throwErrorWithCallback("Could not find template descriptor: form");
- }
-
- var renderedDomElement = Alpaca.tmpl(this.formDescriptor, {
- id: this.getId(),
- options: this.options,
- view: this.view
- });
- renderedDomElement.appendTo(parentEl);
-
- this.form = renderedDomElement;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.formFieldsContainer = $(this.form).find("." + Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
- this.formFieldsContainer.removeClass(Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
-
- if (Alpaca.isEmpty(this.form.attr("id")))
- {
- this.form.attr("id", this.getId() + "-form-outer");
- }
- if (Alpaca.isEmpty(this.form.attr("data-alpaca-form-id")))
- {
- this.form.attr("data-alpaca-form-id", this.getId());
- }
-
- // the form field
- parentEl.find("form").attr(this.attributes);
-
- // populate the buttons as well
- this.buttons = {};
- $(parentEl).find(".alpaca-form-button").each(function() {
-
- $(this).click(function(e) {
- $(this).attr("button-pushed", true);
- });
-
- // custom click handler?
- var key = $(this).attr("data-key");
- if (key)
- {
- var buttonConfig = self.options.buttons[key];
- if (buttonConfig)
- {
- if (buttonConfig.click)
- {
- $(this).click(function(form, handler) {
- return function(e) {
- e.preventDefault();
- handler.call(form, e);
- }
- }(self, buttonConfig.click));
- }
- }
- }
- });
-
- callback();
- },
-
- /**
- * Returns the id of the form.
- *
- * @returns {String} Form id
- */
- getId: function()
- {
- return this.id;
- },
-
- /**
- * Returns form type.
- *
- * @returns {String} Form type.
- */
- getType: function()
- {
- return this.type;
- },
-
- /**
- * Returns this form's parent.
- *
- * @returns {Object} Form parent.
- */
- getParent: function()
- {
- return this.parent;
- },
-
- /**
- * Returns the value of the JSON rendered by this form.
- *
- * @returns {Any} Value of the JSON rendered by this form.
- */
- getValue: function()
- {
- return this.topControl.getValue();
- },
-
- /**
- * Sets the value of the JSON to be rendered by this form.
- *
- * @param {Any} value Value to be set.
- */
- setValue: function(value)
- {
- this.topControl.setValue(value);
- },
-
- /**
- * Initializes events handling (Form Submission) for this form.
- */
- initEvents: function()
- {
- var _this = this;
-
- var formTag = $(this.domEl).find("form");
-
- var v = this.getValue();
- $(formTag).submit(v, function(e) {
- return _this.onSubmit(e, _this);
- });
-
- // listen for fieldupdates and determine whether the form is valid.
- // if so, enable the submit button...
- // otherwise, disable it
- if (this.options.toggleSubmitValidState)
- {
- $(_this.topControl.getFieldEl()).bind("fieldupdate", function() {
- _this.adjustSubmitButtonState();
- });
-
- this.adjustSubmitButtonState();
- }
- },
-
- getButtonEl: function(buttonId)
- {
- return $(this.domEl).find(".alpaca-form-button-" + buttonId);
- },
-
- /**
- * Handles form submit events.
- *
- * @param {Object} e Submit event.
- * @param {Object} form the form
- */
- onSubmit: function(e, form)
- {
- if (this.submitHandler)
- {
- e.stopPropagation();
-
- var v = this.submitHandler(e, form);
- if (Alpaca.isUndefined(v)) {
- v = false;
- }
-
- return v;
- }
- },
-
- /**
- * Registers a custom submit handler.
- *
- * @param {Object} func Submit handler to be registered.
- */
- registerSubmitHandler: function (func)
- {
- if (Alpaca.isFunction(func))
- {
- this.submitHandler = func;
- }
- },
-
- /**
- * Displays validation information of all fields of this form.
- *
- * @param {Boolean} children whether to render validation state for child fields
- *
- * @returns {Object} Form validation state.
- */
- refreshValidationState: function(children, callback)
- {
- this.topControl.refreshValidationState(children, callback);
- },
-
- /**
- * Disables this form.
- */
- disable: function()
- {
- this.topControl.disable();
- },
-
- /**
- * Enables this form.
- */
- enable: function()
- {
- this.topControl.enable();
- },
-
- /**
- * Focuses on this form.
- */
- focus: function()
- {
- this.topControl.focus();
- },
-
- /**
- * Purge any event listeners and remove the form from the DOM.
- *
- * @param [Boolean] skipParent when true, the form cleans up without traversing through parent child controls
- */
- destroy: function(skipParent)
- {
- this.getFormEl().remove();
-
- // we allow form.destroy() which tells parent control to destroy
- // if skipParent == true, then we do not call up (invoked from container)
- if (!skipParent && this.parent)
- {
- this.parent.destroy();
- }
- },
-
- /**
- * Shows the form.
- */
- show: function()
- {
- this.getFormEl().css({
- "display": ""
- });
- },
-
- /**
- * Hides the form.
- */
- hide: function()
- {
- this.getFormEl().css({
- "display": "none"
- });
- },
-
- /**
- * Clears the form and resets values of its fields.
- *
- * @param stopUpdateTrigger If false, triggers the update event of this event.
- */
- clear: function(stopUpdateTrigger)
- {
- this.topControl.clear(stopUpdateTrigger);
- },
-
- /**
- * Checks if form is empty.
- *
- * @returns {Boolean} True if the form is empty, false otherwise.
- */
- isEmpty: function()
- {
- return this.topControl.isEmpty();
- },
-
- /**
- * Fires a view callback for the current form.
- *
- * @param id
- * @param arg1
- * @param arg2
- * @param arg3
- * @param arg4
- * @param arg5
- */
- fireCallback: function(id, arg1, arg2, arg3, arg4, arg5)
- {
- this.view.fireCallback(this, id, arg1, arg2, arg3, arg4, arg5);
- },
-
- /**
- * Retrieves the form element.
- *
- * @returns {Object} The rendered DOM element.
- */
- getFormEl: function() {
- return this.form;
- },
-
- /**
- * Performs a regular old submit.
- */
- submit: function()
- {
- this.form.submit();
- },
-
- /**
- * Fires the submit in the background and hands back the jQuery promise.
- *
- * @returns {*}
- */
- ajaxSubmit: function()
- {
- var self = this;
-
- return $.ajax({
- data: this.getValue(),
- url: self.options.attributes.action,
- type: self.options.attributes.method,
- dataType: "json"
- });
- }
-
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.TextField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "text";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
-
- /*
- if (!this.options.size) {
- this.options.size = 40;
- }
- */
-
- // assume html5 input type = "text"
- if (!this.inputType)
- {
- this.inputType = "text";
- }
-
- if (this.options.inputType)
- {
- this.inputType = this.options.inputType;
- }
-
- // DOM data-* attributes support
- if (!this.options.data)
- {
- this.options.data = {};
- }
-
- // DOM * attributes support
- if (!this.options.attributes)
- {
- this.options.attributes = {};
- }
-
- if (typeof(this.options.allowOptionalEmpty) == "undefined")
- {
- this.options.allowOptionalEmpty = true;
- }
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- this.base();
-
- // clean up typeahead
- if ( this.control && this.control.typeahead && this.options.typeahead)
- {
- $(this.control).typeahead('destroy');
- }
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- if (self.control)
- {
- // mask
- self.applyMask();
-
- // typeahead
- self.applyTypeAhead();
-
- // update max length indicator
- self.updateMaxLengthIndicator();
- }
-
- callback();
- });
- },
-
- applyMask: function()
- {
- var self = this;
-
- // mask it
- if (self.control.mask && self.options.maskString)
- {
- self.control.mask(self.options.maskString);
- }
- },
-
- applyTypeAhead: function()
- {
- var self = this;
-
- if (self.control.typeahead && self.options.typeahead && !Alpaca.isEmpty(self.options.typeahead))
- {
- var tConfig = self.options.typeahead.config;
- if (!tConfig) {
- tConfig = {};
- }
-
- var tDatasets = self.options.typeahead.datasets;
- if (!tDatasets) {
- tDatasets = {};
- }
-
- if (!tDatasets.name) {
- tDatasets.name = self.getId();
- }
-
- var tEvents = self.options.typeahead.events;
- if (!tEvents) {
- tEvents = {};
- }
-
- // support for each datasets (local, remote, prefetch)
- if (tDatasets.type === "local" || tDatasets.type === "remote" || tDatasets.type === "prefetch")
- {
- var bloodHoundConfig = {
- datumTokenizer: function(d) {
- return Bloodhound.tokenizers.whitespace(d.value);
- },
- queryTokenizer: Bloodhound.tokenizers.whitespace
- };
-
- if (tDatasets.type === "local" )
- {
- var local = [];
-
- if (typeof(tDatasets.source) === "function")
- {
- bloodHoundConfig.local = tDatasets.source;
- }
- else
- {
- // array
- for (var i = 0; i < tDatasets.source.length; i++)
- {
- var localElement = tDatasets.source[i];
- if (typeof(localElement) === "string")
- {
- localElement = {
- "value": localElement
- };
- }
-
- local.push(localElement);
- }
-
- bloodHoundConfig.local = local;
- }
-
- if (tDatasets.local)
- {
- bloodHoundConfig.local = tDatasets.local;
- }
- }
-
- if (tDatasets.type === "prefetch")
- {
- bloodHoundConfig.prefetch = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.prefetch.filter = tDatasets.filter;
- }
- }
-
- if (tDatasets.type === "remote")
- {
- bloodHoundConfig.remote = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.remote.filter = tDatasets.filter;
- }
-
- if (tDatasets.replace)
- {
- bloodHoundConfig.remote.replace = tDatasets.replace;
- }
- }
-
- var engine = new Bloodhound(bloodHoundConfig);
- engine.initialize();
- tDatasets.source = engine.ttAdapter();
- }
-
- // compile templates
- if (tDatasets.templates)
- {
- for (var k in tDatasets.templates)
- {
- var template = tDatasets.templates[k];
- if (typeof(template) === "string")
- {
- tDatasets.templates[k] = Handlebars.compile(template);
- }
- }
- }
-
- // process typeahead
- $(self.control).typeahead(tConfig, tDatasets);
-
- // listen for "autocompleted" event and set the value of the field
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // listen for "selected" event and set the value of the field
- $(self.control).on("typeahead:selected", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // custom events
- if (tEvents)
- {
- if (tEvents.autocompleted) {
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- tEvents.autocompleted(event, datum);
- });
- }
- if (tEvents.selected) {
- $(self.control).on("typeahead:selected", function(event, datum) {
- tEvents.selected(event, datum);
- });
- }
- }
-
- // when the input value changes, change the query in typeahead
- // this is to keep the typeahead control sync'd with the actual dom value
- // only do this if the query doesn't already match
- var fi = $(self.control);
- $(self.control).change(function() {
-
- var value = $(this).val();
-
- var newValue = $(fi).typeahead('val');
- if (newValue !== value)
- {
- $(fi).typeahead('val', newValue);
- }
-
- });
-
- // some UI cleanup (we don't want typeahead to restyle)
- $(self.field).find("span.twitter-typeahead").first().css("display", "block"); // SPAN to behave more like DIV, next line
- $(self.field).find("span.twitter-typeahead input.tt-input").first().css("background-color", "");
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.inputType = self.inputType;
-
- callback(model);
- });
- },
-
- updateMaxLengthIndicator: function()
- {
- var self = this;
-
- var errState = false;
-
- var message = "";
- if (!Alpaca.isEmpty(self.schema.maxLength) && self.options.showMaxLengthIndicator)
- {
- var val = self.getValue() || "";
-
- var diff = self.schema.maxLength - val.length;
- if (diff >= 0)
- {
- message = "You have " + diff + " characters remaining";
- }
- else
- {
- message = "Your message is too long by " + (diff*-1) + " characters";
- errState = true;
- }
-
- var indicator = $(self.field).find(".alpaca-field-text-max-length-indicator");
- if (indicator.length === 0)
- {
- indicator = $("");
- $(self.control).after(indicator);
- }
-
- $(indicator).html(message);
- $(indicator).removeClass("err");
- if (errState)
- {
- $(indicator).addClass("err");
- }
- }
-
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!this.isDisplayOnly() && this.control && this.control.length > 0)
- {
- value = this._getControlVal(true);
-
- if (self.control.mask && self.options.maskString)
- {
- // get unmasked value
- var fn = $(this.control).data($.mask.dataName);
- if (fn)
- {
- value = fn();
- value = self.ensureProperType(value);
- }
- }
- }
- else
- {
- value = this.base();
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (this.control && this.control.length > 0)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
- }
-
- // be sure to call into base method
- this.base(value);
-
- // if applicable, update the max length indicator
- this.updateMaxLengthIndicator();
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validatePattern();
- valInfo["invalidPattern"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidPattern"), [this.schema.pattern]),
- "status": status
- };
-
- status = this._validateMaxLength();
- valInfo["stringTooLong"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooLong"), [this.schema.maxLength]),
- "status": status
- };
-
- status = this._validateMinLength();
- valInfo["stringTooShort"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooShort"), [this.schema.minLength]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidPattern"]["status"] && valInfo["stringTooLong"]["status"] && valInfo["stringTooShort"]["status"];
- },
-
- /**
- * Validates against the schema pattern property.
- *
- * @returns {Boolean} True if it matches the pattern, false otherwise.
- */
- _validatePattern: function()
- {
- if (this.schema.pattern)
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (!val.match(this.schema.pattern))
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates against the schema minLength property.
- *
- * @returns {Boolean} True if its size is greater than minLength, false otherwise.
- */
- _validateMinLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.minLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length < this.schema.minLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates against the schema maxLength property.
- *
- * @returns {Boolean} True if its size is less than maxLength , false otherwise.
- */
- _validateMaxLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.maxLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length > this.schema.maxLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- if (this.control && this.control.length > 0)
- {
- // focuses the control and also positions the input at the end
-
- var el = $(this.control).get(0);
-
- try {
- var elemLen = el.value ? el.value.length : 0;
- el.selectionStart = elemLen;
- el.selectionEnd = elemLen;
- }
- catch (e) {
- // field type doesn't support selection start and end
- }
-
- el.focus();
- }
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyDown: function(e)
- {
- var self = this;
-
- if (e.keyCode === 8) // backspace
- {
- if (!Alpaca.isEmpty(self.schema.minLength) && (self.options.constrainLengths || self.options.constrainMinLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length <= self.schema.minLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- else
- {
- if (!Alpaca.isEmpty(self.schema.maxLength) && (self.options.constrainLengths || self.options.constrainMaxLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length >= self.schema.maxLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- },
-
- onKeyUp: function(e)
- {
- var self = this;
-
- // if applicable, update the max length indicator
- self.updateMaxLengthIndicator();
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Single-Line Text";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Text field for single-line text.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minLength": {
- "title": "Minimal Length",
- "description": "Minimal length of the property value.",
- "type": "number"
- },
- "maxLength": {
- "title": "Maximum Length",
- "description": "Maximum length of the property value.",
- "type": "number"
- },
- "pattern": {
- "title": "Pattern",
- "description": "Regular expression for the property value.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "default": {
- "helper": "Field default value",
- "type": "text"
- },
- "minLength": {
- "type": "integer"
- },
- "maxLength": {
- "type": "integer"
- },
- "pattern": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "size": {
- "title": "Field Size",
- "description": "Field size.",
- "type": "number",
- "default":40
- },
- "maskString": {
- "title": "Mask Expression",
- "description": "Expression for the field mask. Field masking will be enabled if not empty.",
- "type": "string"
- },
- "placeholder": {
- "title": "Field Placeholder",
- "description": "Field placeholder.",
- "type": "string"
- },
- "typeahead": {
- "title": "Type Ahead",
- "description": "Provides configuration for the $.typeahead plugin if it is available. For full configuration options, see: https://github.com/twitter/typeahead.js"
- },
- "allowOptionalEmpty": {
- "title": "Allow Optional Empty",
- "description": "Allows this non-required field to validate when the value is empty"
- },
- "inputType": {
- "title": "HTML5 Input Type",
- "description": "Allows for the override of the underlying HTML5 input type. If not specified, an assumed value is provided based on the kind of input control (i.e. 'text', 'date', 'email' and so forth)",
- "type": "string"
- },
- "data": {
- "title": "Data attributes for the underlying DOM input control",
- "description": "Allows you to specify a key/value map of data attributes that will be added as DOM attribuets for the underlying input control. The data attributes will be added as data-{name}='{value}'.",
- "type": "object"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "size": {
- "type": "integer"
- },
- "maskString": {
- "helper": "a - an alpha character;9 - a numeric character;* - an alphanumeric character",
- "type": "text"
- },
- "typeahead": {
- "type": "object"
- },
- "allowOptionalEmpty": {
- "type": "checkbox"
- },
- "inputType": {
- "type": "text"
- },
- "data": {
- "type": "object"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "invalidPattern": "This field should have pattern {0}",
- "stringTooShort": "This field should contain at least {0} numbers or characters",
- "stringTooLong": "This field should contain at most {0} numbers or characters"
- });
- Alpaca.registerFieldClass("text", Alpaca.Fields.TextField);
- Alpaca.registerDefaultSchemaFieldMapping("string", "text");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextAreaField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.TextAreaField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function()
- {
- return "textarea";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.options.rows) {
- this.options.rows = 5;
- }
-
- if (!this.options.cols) {
- this.options.cols = 40;
- }
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": status
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"];
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.data;
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Multi-Line Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Textarea field for multiple line text.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rows": {
- "title": "Rows",
- "description": "Number of rows",
- "type": "number",
- "default": 5
- },
- "cols": {
- "title": "Columns",
- "description": "Number of columns",
- "type": "number",
- "default": 40
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rows": {
- "type": "integer"
- },
- "cols": {
- "type": "integer"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded."
- });
-
- Alpaca.registerFieldClass("textarea", Alpaca.Fields.TextAreaField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CheckBoxField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.CheckBoxField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "checkbox";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function() {
-
- var _this = this;
-
- _this.base();
-
- if (!this.options.rightLabel) {
- this.options.rightLabel = "";
- }
-
- if (typeof(_this.options.multiple) == "undefined")
- {
- if (_this.schema.type === "array")
- {
- _this.options.multiple = true;
- }
- else if (typeof(_this.schema["enum"]) != "undefined")
- {
- _this.options.multiple = true;
- }
- }
-
- _this.checkboxOptions = [];
- if (_this.options.multiple)
- {
- $.each(_this.getEnum(), function(index, value) {
-
- var text = value;
-
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.checkboxOptions.push({
- "value": value,
- "text": text
- });
- });
- }
- },
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- var array = [];
-
- if (this.schema && this.schema["enum"])
- {
- array = this.schema["enum"];
- }
-
- return array;
- },
-
- /**
- * Handler for the event that the checkbox is clicked.
- *
- * @param e Event.
- */
- onClick: function(e)
- {
- this.refreshValidationState();
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
- model.checkboxOptions = self.checkboxOptions;
-
- callback(model);
- });
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the checked state of the control to update
- if (self.data && typeof(self.data) !== "undefined")
- {
- self.setValue(self.data);
- }
-
- // whenever the state of one of our input:checkbox controls is changed (either via a click or programmatically),
- // we signal to the top-level field to fire up a change
- //
- // this allows the dependency system to recalculate and such
- //
- $(self.getFieldEl()).find("input:checkbox").change(function(evt) {
- self.triggerWithPropagation("change");
- });
-
- // for multiple mode, mark values
- if (self.options.multiple)
- {
- // none checked
- $(self.getFieldEl()).find("input:checkbox").prop("checked", false);
-
- if (self.data)
- {
- var dataArray = self.data;
- if (typeof(self.data) === "string")
- {
- dataArray = self.data.split(",");
- for (var a = 0; a < dataArray.length; a++)
- {
- dataArray[a] = $.trim(dataArray[a]);
- }
- }
-
- for (var k in dataArray)
- {
- $(self.getFieldEl()).find("input:checkbox[data-checkbox-value=\"" + dataArray[k] + "\"]").prop("checked", true);
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!self.options.multiple)
- {
- // single scalar value
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- value = Alpaca.checked($(input[0]));
- }
- else
- {
- value = false;
- }
- }
- else
- {
- // multiple values
- var values = [];
- for (var i = 0; i < self.checkboxOptions.length; i++)
- {
- var inputField = $(self.getFieldEl()).find("input[data-checkbox-index='" + i + "']");
- if (Alpaca.checked(inputField))
- {
- var v = $(inputField).attr("data-checkbox-value");
- values.push(v);
- }
- }
-
- // determine how we're going to hand this value back
-
- // if type == "array", we just hand back the array
- // if type == "string", we build a comma-delimited list
- if (self.schema.type === "array")
- {
- value = values;
- }
- else if (self.schema.type === "string")
- {
- value = values.join(",");
- }
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- // value can be a boolean, string ("true"), string ("a,b,c") or an array of values
-
- var applyScalarValue = function(value)
- {
- if (Alpaca.isString(value)) {
- value = (value === "true");
- }
-
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- };
-
- var applyMultiValue = function(values)
- {
- // allow for comma-delimited strings
- if (typeof(values) === "string")
- {
- values = values.split(",");
- }
-
- // trim things to remove any excess white space
- for (var i = 0; i < values.length; i++)
- {
- values[i] = Alpaca.trim(values[i]);
- }
-
- // walk through values and assign into appropriate inputs
- for (var j = 0; j < values.length; j++)
- {
- var input = $(self.getFieldEl()).find("input[data-checkbox-value=\"" + values[j] + "\"]");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- }
- };
-
- var applied = false;
-
- if (!self.options.multiple)
- {
- // single value mode
-
- // boolean
- if (typeof(value) === "boolean")
- {
- applyScalarValue(value);
- applied = true;
- }
- else if (typeof(value) === "string")
- {
- applyScalarValue(value);
- applied = true;
- }
- }
- else
- {
- // multiple value mode
-
- if (typeof(value) === "string")
- {
- applyMultiValue(value);
- applied = true;
- }
- else if (Alpaca.isArray(value))
- {
- applyMultiValue(value);
- applied = true;
- }
- }
-
- if (!applied && value)
- {
- Alpaca.logError("CheckboxField cannot set value for schema.type=" + self.schema.type + " and value=" + value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * Validate against enum property in the case that the checkbox field is in multiple mode.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var self = this;
-
- if (!self.options.multiple)
- {
- return true;
- }
-
- var val = self.getValue();
- if (!self.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- // if val is a string, convert to array
- if (typeof(val) === "string")
- {
- val = val.split(",");
- }
-
- return Alpaca.anyEquality(val, self.schema["enum"]);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = true;
- });
-
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = false;
- });
-
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "boolean";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Checkbox Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Checkbox Field for boolean (true/false), string ('true', 'false' or comma-delimited string of values) or data array.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rightLabel": {
- "title": "Option Label",
- "description": "Optional right-hand side label for single checkbox field.",
- "type": "string"
- },
- "multiple": {
- "title": "Multiple",
- "description": "Whether to render multiple checkboxes for multi-valued type (such as an array or a comma-delimited string)",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rightLabel": {
- "type": "text"
- },
- "multiple": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("checkbox", Alpaca.Fields.CheckBoxField);
- Alpaca.registerDefaultSchemaFieldMapping("boolean", "checkbox");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.FileField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.FileField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "file";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- this.data = value;
-
- this.data = value;
-
- this.updateObservable();
-
- this.triggerUpdate();
- },
-
- getValue: function()
- {
- return this.data;
- },
-
- onChange: function(e)
- {
- this.base(e);
-
- if (this.options.selectionHandler)
- {
- this.processSelectionHandler(e.target.files);
- }
- },
-
- processSelectionHandler: function(files)
- {
- if (files && files.length > 0)
- {
- // if the browser supports HTML5 FileReader, we can pull in the stream for preview
- if (typeof(FileReader) !== "undefined")
- {
- // clear out previous loaded data
- var loadedData = [];
- var loadCount = 0;
-
- var fileReader = new FileReader();
- fileReader.onload = (function() {
- var field = this;
- return function(event)
- {
- var dataUri = event.target.result;
-
- loadedData.push(dataUri);
- loadCount++;
-
- if (loadCount === files.length)
- {
- field.options.selectionHandler.call(field, files, loadedData);
- }
- };
- }).call(this);
-
- for (var i = 0; i < files.length; i++)
- {
- fileReader.readAsDataURL(files[i]);
- }
- }
- }
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "File Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for uploading files.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "selectionHandler": {
- "title": "Selection Handler",
- "description": "Function that should be called when files are selected. Requires HTML5.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "selectionHandler": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("file", Alpaca.Fields.FileField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ListField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ListField.prototype
- */
- {
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var _this = this;
-
- _this.base();
-
- _this.selectOptions = [];
-
- if (_this.getEnum())
- {
- $.each(_this.getEnum(), function(index, value)
- {
- var text = value;
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.selectOptions.push({
- "value": value,
- "text": text
- });
- });
- }
-
- /**
- * Auto assign data if we have data and the field is required and removeDefaultNone is either unspecified or true
- */
- if (_this.isRequired() && !_this.data)
- {
- //if ((typeof(_this.options.removeDefaultNone) == "undefined") || _this.options.removeDefaultNone === true)
- if ((_this.options.removeDefaultNone === true))
- {
- if (_this.schema.enum && _this.schema.enum.length > 0)
- {
- _this.data = _this.schema.enum[0];
- }
- }
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.noneLabel = "None";
- if (typeof(self.options.noneLabel) != "undefined")
- {
- model.noneLabel = self.options.noneLabel;
- }
-
- model.hideNone = self.isRequired();
- if (typeof(self.options.removeDefaultNone) != "undefined")
- {
- model.hideNone = self.options.removeDefaultNone;
- }
-
- callback(model);
- });
- },
-
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- if (this.schema && this.schema["enum"])
- {
- return this.schema["enum"];
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function(val)
- {
- var _this = this;
- if (Alpaca.isArray(val))
- {
- $.each(val, function(index, itemVal) {
- $.each(_this.selectOptions, function(index2, selectOption) {
-
- if (selectOption.value === itemVal)
- {
- val[index] = selectOption.value;
- }
-
- });
- });
- }
- else
- {
- $.each(this.selectOptions, function(index, selectOption) {
-
- if (selectOption.value === val)
- {
- val = selectOption.value;
- }
-
- });
- }
- return val;
- },
-
- /**
- * @see Alpaca.ControlField#beforeRenderControl
- */
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.options.dataSource)
- {
- self.selectOptions = [];
-
- var completionFunction = function()
- {
- self.schema.enum = [];
- self.options.optionLabels = [];
-
- for (var i = 0; i < self.selectOptions.length; i++)
- {
- self.schema.enum.push(self.selectOptions[i].value);
- self.options.optionLabels.push(self.selectOptions[i].text);
- }
-
- // push back to model
- model.selectOptions = self.selectOptions;
-
- callback();
- };
-
- if (Alpaca.isFunction(self.options.dataSource))
- {
- self.options.dataSource.call(self, function(values) {
-
- if (Alpaca.isArray(values))
- {
- for (var i = 0; i < values.length; i++)
- {
- if (typeof(values[i]) === "string")
- {
- self.selectOptions.push({
- "text": values[i],
- "value": values[i]
- });
- }
- else if (Alpaca.isObject(values[i]))
- {
- self.selectOptions.push(values[i]);
- }
- }
-
- completionFunction();
- }
- else if (Alpaca.isObject(values))
- {
- for (var k in values)
- {
- self.selectOptions.push({
- "text": k,
- "value": values[k]
- });
- }
-
- completionFunction();
- }
- else
- {
- completionFunction();
- }
- });
- }
- else if (Alpaca.isUri(self.options.dataSource))
- {
- $.ajax({
- url: self.options.dataSource,
- type: "get",
- dataType: "json",
- success: function(jsonDocument) {
-
- var ds = jsonDocument;
- if (self.options.dsTransformer && Alpaca.isFunction(self.options.dsTransformer))
- {
- ds = self.options.dsTransformer(ds);
- }
-
- if (ds)
- {
- if (Alpaca.isObject(ds))
- {
- // for objects, we walk through one key at a time
- // the insertion order is the order of the keys from the map
- // to preserve order, consider using an array as below
- $.each(ds, function(key, value) {
- self.selectOptions.push({
- "value": key,
- "text": value
- });
- });
-
- completionFunction();
- }
- else if (Alpaca.isArray(ds))
- {
- // for arrays, we walk through one index at a time
- // the insertion order is dictated by the order of the indices into the array
- // this preserves order
- $.each(ds, function(index, value) {
- self.selectOptions.push({
- "value": value.value,
- "text": value.text
- });
- });
-
- completionFunction();
- }
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
-
- self.errorCallback({
- "message":"Unable to load data from uri : " + _this.options.dataSource,
- "stage": "DATASOURCE_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- });
- }
- else if (Alpaca.isArray(self.options.dataSource))
- {
- for (var i = 0; i < self.options.dataSource.length; i++)
- {
- if (typeof(self.options.dataSource[i]) === "string")
- {
- self.selectOptions.push({
- "text": self.options.dataSource[i],
- "value": self.options.dataSource[i]
- });
- }
- else if (Alpaca.isObject(self.options.dataSource[i]))
- {
- self.selectOptions.push(self.options.dataSource[i]);
- }
- }
-
- completionFunction();
- }
- else
- {
- callback();
- }
- }
- else
- {
- callback();
- }
-
- });
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumeration",
- "description": "List of field value options",
- "type": "array",
- "required": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "optionLabels": {
- "title": "Option Labels",
- "description": "Labels for options. It can either be a map object or an array field that maps labels to items defined by enum schema property one by one.",
- "type": "array"
- },
- "dataSource": {
- "title": "Option Datasource",
- "description": "Datasource for generating list of options. This can be a string or a function. If a string, it is considered to be a URI to a service that produces a object containing key/value pairs or an array of elements of structure {'text': '', 'value': ''}. This can also be a function that is called to produce the same list.",
- "type": "string"
- },
- "removeDefaultNone": {
- "title": "Remove Default None",
- "description": "If true, the default 'None' option will not be shown.",
- "type": "boolean",
- "default": false
- },
- "noneLabel": {
- "title": "None Label",
- "description": "The label to use for the 'None' option in a list (select, radio or otherwise).",
- "type": "string",
- "default": "None"
- },
- "hideNone": {
- "title": "Hide None",
- "description": "Whether to hide the None option from a list (select, radio or otherwise). This will be true if the field is required and false otherwise.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "optionLabels": {
- "itemLabel":"Label",
- "type": "array"
- },
- "dataSource": {
- "type": "text"
- },
- "removeDefaultNone": {
- "type": "checkbox",
- "rightLabel": "Remove Default None"
- },
- "noneLabel": {
- "type": "text"
- },
- "hideNone": {
- "type": "checkbox",
- "rightLabel": "Hide the 'None' option from the list"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-})(jQuery);
-
-(function($){
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.RadioField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.RadioField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "radio";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.options.name)
- {
- this.name = this.options.name;
- }
- else if (!this.name)
- {
- this.name = this.getId() + "-name";
- }
-
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.emptySelectFirst))
- {
- this.options.emptySelectFirst = false;
- }
-
- // assume vertical orientation
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.vertical))
- {
- this.options.vertical = true;
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var val = null;
-
- $(this.control).find(":checked").each(function() {
- val = $(this).val();
-
- val = self.ensureProperType(val);
- });
-
- return val;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- var self = this;
-
- // clear all
- $(this.control).find("input").each(function() {
- Alpaca.checked($(this), null);
- });
-
- // mark selected value
- if (typeof(val) != "undefined")
- {
- Alpaca.checked($(self.control).find("input[value=\"" + val + "\"]"), "checked");
- }
-
- // if none selected and "emptySelectFirst", then select
- if (this.options.emptySelectFirst)
- {
- if ($(this.control).find("input:checked").length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio").first(), "checked");
- }
- }
-
- this.base(val);
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- var inputs = $(this.control).find("input");
-
- inputs.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- inputs.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
- model.removeDefaultNone = self.options.removeDefaultNone;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
-
- if ($("input:radio:checked", self.control).length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio[value=\"" + self.data + "\"]"), "checked");
- }
- }
-
- // stack radio selectors vertically
- if (self.options.vertical)
- {
- $(self.control).css("display", "block");
- }
- else
- {
- $(self.control).css("display", "inline-block");
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.ControlField#onClick
- */
- onClick: function(e)
- {
- this.base(e);
-
- var self = this;
-
- var val = $(e.currentTarget).find("input").val();
- if (typeof(val) != "undefined")
- {
- self.setValue(val);
- self.refreshValidationState();
- }
-
- /*
- Alpaca.later(25, this, function(){
- var v = self.getValue();
- self.setValue(v);
- self.refreshValidationState();
- });
- */
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Radio Group Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Radio Group Field with list of options.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function()
- {
- return Alpaca.merge(this.base(),{
- "properties": {
- "name": {
- "title": "Field name",
- "description": "Field name.",
- "type": "string"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "vertical": {
- "title": "Position the radio selector items vertically",
- "description": "By default, radio controls are stacked vertically. Set to false if you'd like radio controls to lay out horizontally.",
- "type": "boolean",
- "default": true
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("radio", Alpaca.Fields.RadioField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SelectField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.SelectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function()
- {
- return "select";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- if (this.control && this.control.length > 0)
- {
- var val = this._getControlVal(true);
- if (typeof(val) === "undefined")
- {
- val = this.data;
- }
-
- return this.base(val);
- }
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- if (Alpaca.isArray(val))
- {
- if (!Alpaca.compareArrayContent(val, this.getValue()))
- {
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- else
- {
- if (val !== this.getValue())
- {
- /*
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
- */
- if (this.control && typeof(val) != "undefined" && val != null)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- },
-
- /**
- * @see Alpaca.ListField#getEnum
- */
- getEnum: function()
- {
- if (this.schema)
- {
- if (this.schema["enum"])
- {
- return this.schema["enum"];
- }
- else if (this.schema["type"] && this.schema["type"] === "array" && this.schema["items"] && this.schema["items"]["enum"])
- {
- return this.schema["items"]["enum"];
- }
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- if (self.options.multiple)
- {
- var button = this.control.parent().find("button.multiselect");
-
- button.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- button.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- }
- },
-
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.schema["type"] && self.schema["type"] === "array")
- {
- self.options.multiple = true;
- }
-
- callback();
-
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (Alpaca.isUndefined(self.data) && self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
- }
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the state of the control
- if (self.data)
- {
- self.setValue(self.data);
- }
-
- // if we are in multiple mode and the bootstrap multiselect plugin is available, bind it in
- if (self.options.multiple && $.fn.multiselect)
- {
- var settings = null;
- if (self.options.multiselect) {
- settings = self.options.multiselect;
- }
- else
- {
- settings = {};
- }
- if (!settings.nonSelectedText)
- {
- settings.nonSelectedText = "None";
- if (self.options.noneLabel)
- {
- settings.nonSelectedText = self.options.noneLabel;
- }
- }
- if (self.options.hideNone)
- {
- delete settings.nonSelectedText;
- }
-
- $(self.getControlEl()).multiselect(settings);
- }
-
- callback();
-
- });
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var _this = this;
-
- if (this.schema["enum"])
- {
- var val = this.data;
-
- if (!this.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- if (this.options.multiple)
- {
- var isValid = true;
-
- if (!val)
- {
- val = [];
- }
-
- if (!Alpaca.isArray(val) && !Alpaca.isObject(val))
- {
- val = [val];
- }
-
- $.each(val, function(i,v) {
-
- if ($.inArray(v, _this.schema["enum"]) <= -1)
- {
- isValid = false;
- return false;
- }
-
- });
-
- return isValid;
- }
- else
- {
- return ($.inArray(val, this.schema["enum"]) > -1);
- }
- }
- else
- {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- _this.refreshValidationState();
- });
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if ($(":selected",this.control).length < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if ($(":selected",this.control).length > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Select Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Select Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multiple": {
- "title": "Mulitple Selection",
- "description": "Allow multiple selection if true.",
- "type": "boolean",
- "default": false
- },
- "size": {
- "title": "Displayed Options",
- "description": "Number of options to be shown.",
- "type": "number"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "multiselect": {
- "title": "Multiselect Plugin Settings",
- "description": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multiple": {
- "rightLabel": "Allow multiple selection ?",
- "helper": "Allow multiple selection if checked",
- "type": "checkbox"
- },
- "size": {
- "type": "integer"
- },
- "emptySelectFirst": {
- "type": "checkbox",
- "rightLabel": "Empty Select First"
- },
- "multiselect": {
- "type": "object",
- "rightLabel": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("select", Alpaca.Fields.SelectField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.NumberField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.NumberField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "number";
- //this.inputType = "number";
- // TODO: we can't do this because Chrome screws up it's handling of number type
- // and prevents us from validating properly
- // @see http://stackoverflow.com/questions/16420828/jquery-val-refuses-to-return-non-numeric-input-from-a-number-field-under-chrome
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "number";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var val = this._getControlVal(true);
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseFloat(val);
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateNumber();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotANumber"),
- "status": status
- };
-
- status = this._validateDivisibleBy();
- valInfo["stringDivisibleBy"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringDivisibleBy"), [this.schema.divisibleBy]),
- "status": status
- };
-
- status = this._validateMaximum();
- valInfo["stringValueTooLarge"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMaximum) {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLargeExclusive"), [this.schema.maximum]);
- } else {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLarge"), [this.schema.maximum]);
- }
- }
-
- status = this._validateMinimum();
- valInfo["stringValueTooSmall"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMinimum) {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmallExclusive"), [this.schema.minimum]);
- } else {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmall"), [this.schema.minimum]);
- }
- }
-
- status = this._validateMultipleOf();
- valInfo["stringValueNotMultipleOf"] = {
- "message": "",
- "status": status
- };
- if (!status)
- {
- valInfo["stringValueNotMultipleOf"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueNotMultipleOf"), [this.schema.multipleOf]);
- }
-
- // hand back a true/false
- return baseStatus && valInfo["stringNotANumber"]["status"] && valInfo["stringDivisibleBy"]["status"] && valInfo["stringValueTooLarge"]["status"] && valInfo["stringValueTooSmall"]["status"] && valInfo["stringValueNotMultipleOf"]["status"];
- },
-
- /**
- * Validates if it is a float number.
- * @returns {Boolean} true if it is a float number
- */
- _validateNumber: function() {
-
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid number format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.number, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * Validates divisibleBy constraint.
- * @returns {Boolean} true if it passes the divisibleBy constraint.
- */
- _validateDivisibleBy: function() {
- var floatValue = this.getValue();
- if (!Alpaca.isEmpty(this.schema.divisibleBy)) {
-
- // mod
- if (floatValue % this.schema.divisibleBy !== 0)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the maximum constraint.
- */
- _validateMaximum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.maximum)) {
- if (floatValue > this.schema.maximum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMaximum)) {
- if (floatValue == this.schema.maximum && this.schema.exclusiveMaximum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the minimum constraint.
- */
- _validateMinimum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.minimum)) {
- if (floatValue < this.schema.minimum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMinimum)) {
- if (floatValue == this.schema.minimum && this.schema.exclusiveMinimum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates multipleOf constraint.
- * @returns {Boolean} true if it passes the multipleOf constraint.
- */
- _validateMultipleOf: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.multipleOf)) {
- if (floatValue && this.schema.multipleOf !== 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "number";
- },
-
- /* builder_helpers */
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "Property value must be a multiple of the multipleOf schema property such that division by this value yields an interger (mod zero).",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "number"
- },
- "exclusiveMinimum": {
- "title": "Exclusive Minimum",
- "description": "Property value can not equal the number defined by the minimum schema property.",
- "type": "boolean",
- "default": false
- },
- "exclusiveMaximum": {
- "title": "Exclusive Maximum",
- "description": "Property value can not equal the number defined by the maximum schema property.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "The value must be a integral multiple of the property",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property",
- "type": "number"
- },
- "exclusiveMinimum": {
- "rightLabel": "Exclusive minimum ?",
- "helper": "Field value must be greater than but not equal to this number if checked",
- "type": "checkbox"
- },
- "exclusiveMaximum": {
- "rightLabel": "Exclusive Maximum ?",
- "helper": "Field value must be less than but not equal to this number if checked",
- "type": "checkbox"
- }
- }
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Number Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for float numbers.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringValueTooSmall": "The minimum value for this field is {0}",
- "stringValueTooLarge": "The maximum value for this field is {0}",
- "stringValueTooSmallExclusive": "Value of this field must be greater than {0}",
- "stringValueTooLargeExclusive": "Value of this field must be less than {0}",
- "stringDivisibleBy": "The value must be divisible by {0}",
- "stringNotANumber": "This value is not a number.",
- "stringValueNotMultipleOf": "This value is not a multiple of {0}"
- });
- Alpaca.registerFieldClass("number", Alpaca.Fields.NumberField);
- Alpaca.registerDefaultSchemaFieldMapping("number", "number");
-
-})(jQuery);
-
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ArrayField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ArrayField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "array";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = Alpaca.isEmpty(this.view.toolbarStyle) ? "button" : this.view.toolbarStyle;
- }
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = "button";
- }
-
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = Alpaca.isEmpty(this.view.actionbarStyle) ? "top" : this.view.actionbarStyle;
- }
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = "top";
- }
-
- // determine whether we are using "ruby on rails" compatibility mode
- this.options.rubyrails = false;
- if (this.parent && this.parent.options && this.parent.options.form && this.parent.options.form.attributes)
- {
- if (!Alpaca.isEmpty(this.parent.options.form.attributes.rubyrails))
- {
- this.options.rubyrails = true;
- }
- }
-
- if (!this.options.items)
- {
- this.options.items = {};
- }
-
- var toolbarSticky = true;
-
- if (!Alpaca.isEmpty(this.view.toolbarSticky))
- {
- toolbarSticky = this.view.toolbarSticky;
- }
-
- if (!Alpaca.isEmpty(this.options.toolbarSticky))
- {
- toolbarSticky = this.options.toolbarSticky;
- }
-
- this.options.toolbarSticky = toolbarSticky;
-
- // Enable forceRevalidation option so that any change in children will trigger parent's revalidation.
- if (this.schema.items && this.schema.uniqueItems)
- {
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
- }
-
- if (typeof(this.data) == "undefined")
- {
- this.data = [];
- }
-
- if (this.data == null)
- {
- this.data = [];
- }
-
- if ("" == this.data)
- {
- this.data = [];
- }
-
- if (Alpaca.isString(this.data))
- {
- // assume to be a serialized array or object, convert
- try
- {
- var parsedJSON = Alpaca.parseJSON(this.data);
-
- if (!Alpaca.isArray(parsedJSON) && !Alpaca.isObject(parsedJSON))
- {
- Alpaca.logWarn("ArrayField parsed string data but it was not an array: " + this.data);
- return;
- }
-
- this.data = parsedJSON;
- }
- catch (e)
- {
- // assume just a string value, put into array
- this.data = [this.data];
- }
- }
-
- if (!Alpaca.isArray(this.data) && !Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ArrayField data is not an array: " + JSON.stringify(this.data, null, " "));
- return;
- }
-
- //
- // ACTIONS
- //
- var applyAction = function(actions, key, actionConfig) {
- var action = self.findAction(actions, key);
- if (!action) {
- action = {
- "core": true
- };
- actions.push(action);
- }
- for (var k in actionConfig) {
- action[k] = actionConfig[k];
- }
- };
- var cleanupActions = function(actions, showLabels) {
- var i = 0;
- do {
-
- // assume enabled by default
- if (typeof(actions[i].enabled) === "undefined") {
- actions[i].enabled = true;
- }
-
- // hide label if global disable
- if (!showLabels) {
- delete actions[i].label;
- }
-
- if (!actions[i].enabled) {
- actions.splice(i, 1);
- } else {
- i++;
- }
-
- } while (i < actions.length);
-
- // sort so that core actions appear first
- actions.sort(function(a, b) {
- if (a.core && !b.core) {
- return -1;
- }
- if (!a.core && b.core) {
- return 1;
- }
- return 0;
- });
- };
-
- // set up default actions for the top array toolbar
- self.toolbar = {};
- if (self.options.toolbar)
- {
- for (var k in self.options.toolbar) {
- self.toolbar[k] = self.options.toolbar[k];
- }
- }
- if (typeof(self.toolbar.showLabels) === "undefined") {
- self.toolbar.showLabels = false;
- }
- if (!self.toolbar.actions) {
- self.toolbar.actions = [];
- }
- applyAction(self.toolbar.actions, "add", {
- "label": "Add New Item",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action)
- {
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(0, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
- }
- });
- cleanupActions(self.toolbar.actions, self.toolbar.showLabels);
-
- // determine which actions to add into the per-item actionbar
- self.actionbar = {};
- if (self.options.actionbar)
- {
- for (var k2 in self.options.actionbar) {
- self.actionbar[k2] = self.options.actionbar[k2];
- }
- }
- if (typeof(self.actionbar.showLabels) === "undefined") {
- self.actionbar.showLabels = false;
- }
- if (!self.actionbar.actions) {
- self.actionbar.actions = [];
- }
- applyAction(self.actionbar.actions, "add", {
- "label": "Add",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action, itemIndex) {
-
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(itemIndex + 1, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
-
- }
- });
- applyAction(self.actionbar.actions, "remove", {
- "label": "Remove",
- "action": "remove",
- "iconClass": self.view.getStyle("removeIcon"),
- "click": function(key, action, itemIndex) {
-
- self.removeItem(itemIndex, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "up", {
- "label": "Up",
- "action": "up",
- "iconClass": self.view.getStyle("upIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex - 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "down", {
- "label": "Down",
- "action": "down",
- "iconClass": self.view.getStyle("downIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex + 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- cleanupActions(self.actionbar.actions, self.actionbar.showLabels);
-
- var len = this.data.length;
- var data = $.extend(true, {}, this.data);
- data.length = len;
-
- this.data = Array.prototype.slice.call(data);
- },
-
- /**
- * Picks apart the array and set onto child fields.
- * @see Alpaca.ContainerField#setup
- */
- setValue: function(data)
- {
- var self = this;
-
- if (!data || !Alpaca.isArray(data))
- {
- return;
- }
-
- // set fields
- var i = 0;
- do
- {
- if (i < self.children.length)
- {
- var childField = self.children[i];
-
- if (data.length > i)
- {
- childField.setValue(data[i]);
- i++;
- }
- else
- {
- self.removeItem(i);
- }
- }
- }
- while (i < self.children.length);
-
- // if the number of items in the data is greater than the number of existing child elements
- // then we need to add the new fields
- if (i < data.length)
- {
- self.resolveItemSchemaOptions(function(schema, options) {
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for item: " + i);
- }
-
- // waterfall functions
- var funcs = [];
-
- while (i < data.length)
- {
- var f = (function(i, data)
- {
- return function(callback)
- {
- self.addItem(i, schema, options, data[i], function() {
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
- })(i, data[i]);
-
- funcs.push(f);
-
- i++;
- }
-
- Alpaca.series(funcs, function() {
- // nothing
- });
- });
- }
-
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we're empty and we're also not required, then we hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // otherwise, construct an array and had it back
- var o = [];
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
-
- if (typeof(v) !== "undefined")
- {
- o.push(v);
- }
- }
- return o;
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var self = this;
-
- var items = [];
-
- if (self.data)
- {
- // all items within the array have the same schema and options
- // so we only need to load this once
- self.resolveItemSchemaOptions(function(schema, options) {
-
- // waterfall functions
- var funcs = [];
- for (var index = 0; index < self.data.length; index++)
- {
- var value = self.data[index];
-
- var pf = (function(index, value)
- {
- return function(callback)
- {
- self.createItem(index, schema, options, value, function(item) {
-
- items.push(item);
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
-
- })(index, value);
-
- funcs.push(pf);
- }
-
- Alpaca.series(funcs, function(err) {
- callback(items);
- });
-
- });
- }
- else
- {
- callback(items);
- }
- },
-
- /**
- * Workhorse method for createItem.
- *
- * @param index
- * @param itemSchema
- * @param itemOptions
- * @param itemData
- * @param postRenderCallback
- * @return {*}
- * @private
- */
- createItem: function(index, itemSchema, itemOptions, itemData, postRenderCallback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render": function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // setup item path
- fieldControl.path = self.path + "[" + index + "]";
- //fieldControl.nameCalculated = true;
- fieldControl.render(null, function() {
-
- // remember the control
- self.refreshValidationState();
- self.updatePathAndName();
-
- // trigger update on the parent array
- self.triggerUpdate();
-
- if (cb)
- {
- cb();
- }
- });
- },
- "postRender": function(control)
- {
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- // PR: https://github.com/gitana/alpaca/pull/124
- if (Alpaca.isFunction(self.options.items.postRender))
- {
- self.options.items.postRender.call(control, insertionPointEl);
- }
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- }
- },
-
- /**
- * Determines the schema and options to utilize for items within this array.
- *
- * @param callback
- */
- resolveItemSchemaOptions: function(callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedItemSchema, resolvedItemOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedItemOptions.readonly = true;
- }
-
- callback(resolvedItemSchema, resolvedItemOptions, circular);
- };
-
- var itemOptions;
- // legacy support for options.fields.item
- if (!itemOptions && _this.options && _this.options.fields && _this.options.fields.item) {
- itemOptions = _this.options.fields.item;
- }
- if (!itemOptions && _this.options && _this.options.items) {
- itemOptions = _this.options.items;
- }
- var itemSchema;
- if (_this.schema && _this.schema.items) {
- itemSchema = _this.schema.items;
- }
-
- // handle $ref
- if (itemSchema && itemSchema["$ref"])
- {
- var referenceId = itemSchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalItemSchema = itemSchema;
- var originalItemOptions = itemOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(itemSchema, itemOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedItemSchema = {};
- if (originalItemSchema) {
- Alpaca.mergeObject(resolvedItemSchema, originalItemSchema);
- }
- if (itemSchema)
- {
- Alpaca.mergeObject(resolvedItemSchema, itemSchema);
- }
- delete resolvedItemSchema.id;
-
- var resolvedItemOptions = {};
- if (originalItemOptions) {
- Alpaca.mergeObject(resolvedItemOptions, originalItemOptions);
- }
- if (itemOptions)
- {
- Alpaca.mergeObject(resolvedItemOptions, itemOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedItemSchema, resolvedItemOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(itemSchema, itemOptions);
- });
- }
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateUniqueItems();
- valInfo["valueNotUnique"] = {
- "message": status ? "" : this.view.getMessage("valueNotUnique"),
- "status": status
- };
-
- status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["valueNotUnique"]["status"] && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- },
-
- /**
- * Validates if the number of items has been reached to maxItems.
- * @returns {Boolean} true if the number of items has been reached to maxItems
- */
- _validateEqualMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() >= this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if the number of items has been reached to minItems.
- * @returns {Boolean} true if number of items has been reached to minItems
- */
- _validateEqualMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() <= this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if all items are unique.
- * @returns {Boolean} true if all items are unique.
- */
- _validateUniqueItems: function()
- {
- if (this.schema.items && this.schema.uniqueItems)
- {
- var hash = {};
- for (var i = 0, l = this.children.length; i < l; ++i)
- {
- if (!hash.hasOwnProperty(this.children[i]))
- {
- hash[this.children[i]] = true;
- }
- else
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- findAction: function(actionsArray, actionKey)
- {
- var action = null;
-
- $.each(actionsArray, function(i, v) {
- if (v.action == actionKey) // jshint ignore:line
- {
- action = v;
- }
- });
-
- return action;
- },
-
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
-
- });
- },
-
- /*
- afterApplyCreatedItems: function(model, callback)
- {
- var self = this;
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
- },
- */
-
- /**
- * Returns number of children.
- */
- getSize: function() {
- return this.children.length;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updatePathAndName: function()
- {
- var self = this;
-
- var updateChildrenPathAndName = function(parent)
- {
- if (parent.children)
- {
- $.each(parent.children, function(i, v) {
-
- if (parent.prePath && Alpaca.startsWith(v.path,parent.prePath))
- {
- v.prePath = v.path;
- v.path = v.path.replace(parent.prePath,parent.path);
- }
-
- // re-calculate name
- if (parent.preName && Alpaca.startsWith(v.name, parent.preName))
- {
- v.preName = v.name;
- v.name = v.name.replace(parent.preName, parent.name);
- if (v.field)
- {
- $(v.field).attr('name', v.name);
- }
- }
-
- updateChildrenPathAndName(v);
- });
- }
- };
-
- if (this.children && this.children.length > 0)
- {
- $.each(this.children, function(i, v) {
-
- var idx = v.path.lastIndexOf('/');
- var lastSegment = v.path.substring(idx+1);
- if (lastSegment.indexOf("[") < 0 && lastSegment.indexOf("]") < 0)
- {
- lastSegment = lastSegment.substring(lastSegment.indexOf("[") + 1, lastSegment.indexOf("]"));
- }
-
- if (lastSegment !== i)
- {
- v.prePath = v.path;
- v.path = v.path.substring(0, idx) + "/[" + i + "]";
- }
-
- // re-calculate name
- if (v.nameCalculated)
- {
- v.preName = v.name;
-
- if (v.parent && v.parent.name && v.path)
- {
- v.name = v.parent.name + "_" + i;
- }
- else
- {
- if (v.path)
- {
- v.name = v.path.replace(/\//g, "").replace(/\[/g, "_").replace(/\]/g, "");
- }
- }
-
- if (this.parent.options.rubyrails )
- {
- $(v.field).attr('name', v.parent.name);
- }
- else
- {
- $(v.field).attr('name', v.name);
- }
-
- }
-
- if (!v.prePath)
- {
- v.prePath = v.path;
- }
-
- updateChildrenPathAndName(v);
- });
- }
- },
-
- /**
- * Updates the status of array item action toolbar buttons.
- */
- updateToolbars: function()
- {
- var self = this;
-
- // if we're in display mode, we do not do this
- if (this.view.type === "display")
- {
- return;
- }
-
- // if we're in readonly mode, don't do this
- if (this.schema.readonly)
- {
- return;
- }
-
- // fire callbacks to view to remove and create toolbar
- if (self.toolbar)
- {
- self.fireCallback("arrayToolbar", true);
- self.fireCallback("arrayToolbar");
- }
-
- // fire callbacks to view to remove and create an actionbar for each item
- if (self.actionbar)
- {
- self.fireCallback("arrayActionbars", true);
- self.fireCallback("arrayActionbars");
- }
-
- //
- // TOOLBAR
- //
-
- var toolbarEl = $(this.getFieldEl()).find(".alpaca-array-toolbar[data-alpaca-array-toolbar-field-id='" + self.getId() + "']");
- if (this.children.length > 0)
- {
- // hide toolbar
- $(toolbarEl).hide();
- }
- else
- {
- // show toolbar
- $(toolbarEl).show();
-
- // CLICK: array toolbar buttons
- $(toolbarEl).find("[data-alpaca-array-toolbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-toolbar-action");
- var action = self.findAction(self.toolbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action);
- });
- }
- });
- }
-
-
- //
- // ACTIONBAR
- //
-
- // if we're not using the "sticky" toolbar, then show and hide the item action buttons when hovered
- if (!this.options.toolbarSticky)
- {
- // find each item
- var items = this.getFieldEl().find(".alpaca-container-item");
- $(items).each(function(itemIndex) {
-
- // find the actionbar for this item
- // find from containerItemEl
- var actionbarEl = $(self.containerItemEl).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "'][data-alpaca-array-actionbar-item-index='" + itemIndex + "']");
- if (actionbarEl && actionbarEl.length > 0)
- {
- $(this).hover(function() {
- $(actionbarEl).show();
- }, function() {
- $(actionbarEl).hide();
- });
-
- $(actionbarEl).hide();
- }
- });
- }
- else
- {
- // otherwise, always show the actionbars
- $(self.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "']").show();
- }
-
- // CLICK: actionbar buttons
- var actionbarEls = $(this.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-parent-field-id='" + self.getId() + "']");
- $(actionbarEls).each(function() {
-
- var targetIndex = $(this).attr("data-alpaca-array-actionbar-item-index");
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- // bind button click handlers
- $(this).find("[data-alpaca-array-actionbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-actionbar-action");
- var action = self.findAction(self.actionbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action, targetIndex);
- });
- }
- });
-
- // if we're at max capacity, disable "add" buttons
- if (self._validateEqualMaxItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
-
- // if we're at min capacity, disable "remove" buttons
- if (self._validateEqualMinItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
- });
- // first actionbar has its "move up" button disabled
- $(actionbarEls).first().find("[data-alpaca-array-actionbar-action='up']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- // last actionbar has its "move down" button disabled
- $(actionbarEls).last().find("[data-alpaca-array-actionbar-action='down']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
-
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- doResolveItemContainer: function()
- {
- var self = this;
-
- return $(self.container);
- },
-
- doAddItem: function(index, item)
- {
- var self = this;
-
- var addItemContainer = self.doResolveItemContainer();
-
- // insert into dom
- if (index === 0)
- {
- // insert first into container
- $(addItemContainer).append(item.containerItemEl);
- }
- else
- {
- // insert at a specific index
- var existingElement = addItemContainer.children("[data-alpaca-container-item-index='" + (index-1) + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(item.containerItemEl);
- }
- }
-
- self.doAfterAddItem(item);
- },
-
- doAfterAddItem: function(item)
- {
-
- },
-
- /**
- * Adds an item to the array.
- *
- * This gets called from the toolbar when items are added via the user interface. The method can also
- * be called programmatically to insert items on the fly.
- *
- * @param {Integer} index the index where the item should be inserted
- * @param {Object} schema the json schema
- * @param {Object} options the json options
- * @param {Any} data the data for the newly inserted item
- * @param [Function] callback called after the child is added
- */
- addItem: function(index, schema, options, data, callback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- self.createItem(index, schema, options, data, function(item) {
-
- // register the child
- self.registerChild(item, index);
-
- // insert into dom
- self.doAddItem(index, item);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- }
- },
-
- doRemoveItem: function(childIndex)
- {
- var self = this;
-
- var removeItemContainer = self.doResolveItemContainer();
-
- removeItemContainer.children(".alpaca-container-item[data-alpaca-container-item-index='" + childIndex + "']").remove();
- },
-
- /**
- * Removes an item from the array.
- *
- * This gets called automatically from setValue() when the number of items being set is less than the number
- * of field elements.
-
- * @param {Number} childIndex index of the child to be removed
- * @param [Function] callback called after the child is removed
- */
- removeItem: function(childIndex, callback)
- {
- var self = this;
-
- if (this._validateEqualMinItems())
- {
- // unregister the child
- self.unregisterChild(childIndex);
-
- // remove itemContainerEl from DOM
- self.doRemoveItem(childIndex);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- }
- },
-
- /**
- * Dynamically moves a child to a new index in the array.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to be moved to
- * @param {Boolean} animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- if (sourceIndex === targetIndex)
- {
- // nothing to do
- return;
- }
-
- //console.log("Source: " + sourceIndex + ", Target: " + targetIndex);
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- var parentFieldId = self.getId();
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + sourceIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
- var targetContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + targetIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- var duration = 0;
- if (animate)
- {
- duration = 500;
- }
-
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, duration, function() {
- onComplete();
- });
- },
-
- /**
- * @see Alpaca.ContainerField#getType
- */
- getType: function() {
- return "array";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.ContainerField#getTitle
- */
- getTitle: function() {
- return "Array Field";
- },
-
- /**
- * @see Alpaca.ContainerField#getDescription
- */
- getDescription: function() {
- return "Field for list of items with same data type or structure.";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "items": {
- "title": "Array Items",
- "description": "Schema for array items.",
- "type": "object",
- "properties": {
- "minItems": {
- "title": "Minimum Items",
- "description": "Minimum number of items.",
- "type": "number"
- },
- "maxItems": {
- "title": "Maximum Items",
- "description": "Maximum number of items.",
- "type": "number"
- },
- "uniqueItems": {
- "title": "Items Unique",
- "description": "Item values should be unique if true.",
- "type": "boolean",
- "default": false
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "items": {
- "type": "object",
- "fields": {
- "minItems": {
- "type": "integer"
- },
- "maxItems": {
- "type": "integer"
- },
- "uniqueItems": {
- "type": "checkbox"
- }
- }
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var properties = {
- "properties": {
- "toolbarSticky": {
- "title": "Sticky Toolbar",
- "description": "Array item toolbar will be aways on if true.",
- "type": "boolean",
- "default": false
- },
- "toolbarStyle": {
- "title": "Toolbar Style",
- "description": "The kind of top-level toolbar to render for the array field. Either 'button' or 'link'.",
- "type": "string",
- "default": "button"
- },
- "actionbarStyle": {
- "title": "Actionbar Style",
- "description": "The kind of actionbar to render for each item in the array. Either 'top', 'bottom', 'left', or 'right'.",
- "type": "string",
- "default": "top"
- },
- "toolbar": {
- "type": "object",
- "title": "Toolbar Configuration",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Toolbar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- },
- "actionbar": {
- "type": "object",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Actions Bar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "toolbarSticky": {
- "type": "checkbox"
- },
- "items": {
- "type": "object",
- "fields": {
- }
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "notEnoughItems": "The minimum number of items is {0}",
- "tooManyItems": "The maximum number of items is {0}",
- "valueNotUnique": "Values are not unique",
- "notAnArray": "This value is not an Array"
- });
- Alpaca.registerFieldClass("array", Alpaca.Fields.ArrayField);
- Alpaca.registerDefaultSchemaFieldMapping("array", "array");
-
-})(jQuery);
-
-/*jshint -W004 */ // duplicate variables
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ObjectField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ObjectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "object";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- var x = self.resolveContainerItemTemplateType();
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
-
- if (this.data === "")
- {
- return;
- }
-
- if (!Alpaca.isObject(this.data))
- {
- if (!Alpaca.isString(this.data))
- {
- return;
- }
- else
- {
- try
- {
- this.data = Alpaca.parseJSON(this.data);
- if (!Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ObjectField parsed data but it was not an object: " + JSON.stringify(this.data));
- return;
- }
- }
- catch (e)
- {
- return;
- }
- }
- }
- },
-
- /**
- * Picks apart the data object and set onto child fields.
- *
- * @see Alpaca.Field#setValue
- */
- setValue: function(data)
- {
- if (!data)
- {
- data = {};
- }
-
- // if not an object by this point, we don't handle it
- if (!Alpaca.isObject(data))
- {
- return;
- }
-
- // sort existing fields by property id
- var existingFieldsByPropertyId = {};
- for (var fieldId in this.childrenById)
- {
- var propertyId = this.childrenById[fieldId].propertyId;
- existingFieldsByPropertyId[propertyId] = this.childrenById[fieldId];
- }
-
- // new data mapped by property id
- var newDataByPropertyId = {};
- for (var k in data)
- {
- if (data.hasOwnProperty(k))
- {
- newDataByPropertyId[k] = data[k];
- }
- }
-
- // walk through new property ids
- // if a field exists, set value onto it and remove from newDataByPropertyId and existingFieldsByPropertyId
- // if a field doesn't exist, let it remain in list
- for (var propertyId in newDataByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- if (field)
- {
- field.setValue(newDataByPropertyId[propertyId]);
-
- delete existingFieldsByPropertyId[propertyId];
- delete newDataByPropertyId[propertyId];
- }
- }
-
- // anything left in existingFieldsByPropertyId describes data that is missing, null or empty
- // we null out those values
- for (var propertyId in existingFieldsByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- field.setValue(null);
- }
-
- // anything left in newDataByPropertyId is new stuff that we need to add
- // the object field doesn't support this since it runs against a schema
- // so we drop this off
- },
-
- /**
- * Reconstructs the data object from the child fields.
- *
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back empty object
- if (this.children.length === 0 && !this.isRequired())
- {
- return {};
- }
-
- // otherwise, hand back an object with our child properties in it
- var o = {};
-
- // walk through all of the properties object
- // for each property, we insert it into a JSON object that we'll hand back as the result
-
- // if the property has dependencies, then we evaluate those dependencies first to determine whether the
- // resulting property should be included
-
- for (var i = 0; i < this.children.length; i++)
- {
- // the property key and vlaue
- var propertyId = this.children[i].propertyId;
- var fieldValue = this.children[i].getValue();
-
- if (typeof(fieldValue) !== "undefined")
- {
- if (this.determineAllDependenciesValid(propertyId))
- {
- var assignedValue = null;
-
- if (typeof(fieldValue) === "boolean")
- {
- assignedValue = (fieldValue? true: false);
- }
- else if (Alpaca.isArray(fieldValue) || Alpaca.isObject(fieldValue) || Alpaca.isNumber(fieldValue))
- {
- assignedValue = fieldValue;
- }
- else if (fieldValue)
- {
- assignedValue = fieldValue;
- }
-
- if (assignedValue !== null)
- {
- o[propertyId] = assignedValue;
- }
- }
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- // Generates wizard if requested
- if (self.isTopLevel())
- {
- if (self.view)
- {
- self.wizardConfigs = self.view.getWizard();
- if (typeof(self.wizardConfigs) != "undefined")
- {
- if (!self.wizardConfigs || self.wizardConfigs === true)
- {
- self.wizardConfigs = {};
- }
- }
-
- var layoutTemplateDescriptor = self.view.getLayout().templateDescriptor;
- if (self.wizardConfigs && Alpaca.isObject(self.wizardConfigs))
- {
- if (!layoutTemplateDescriptor || self.wizardConfigs.bindings)
- {
- // run the automatic wizard
- self.autoWizard();
- }
- else
- {
- // manual wizard based on layout
- self.wizard();
- }
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var _this = this;
-
- var items = [];
-
- // we keep a map of all of the properties in our original data object
- // as we render elements out of the schema, we remove from the extraDataProperties map
- // whatever is leftover are the data properties that were NOT rendered because they were not part
- // of the schema
- //
- // this is primarily maintained for debugging purposes, so as to inform the developer of mismatches
- var extraDataProperties = {};
- for (var dataKey in _this.data) {
- extraDataProperties[dataKey] = dataKey;
- }
-
- var properties = _this.data;
- if (_this.schema && _this.schema.properties) {
- properties = _this.schema.properties;
- }
-
- var cf = function()
- {
- // If the schema and the data line up perfectly, then there will be no properties in the data that are
- // not also in the schema, and thus, extraDataProperties will be empty.
- //
- // On the other hand, if there are some properties in data that were not in schema, then they will
- // remain in extraDataProperties and we can inform developers for debugging purposes
- //
- var extraDataKeys = [];
- for (var extraDataKey in extraDataProperties) {
- extraDataKeys.push(extraDataKey);
- }
- if (extraDataKeys.length > 0) {
- Alpaca.logDebug("There were " + extraDataKeys.length + " extra data keys that were not part of the schema " + JSON.stringify(extraDataKeys));
- }
-
- callback(items);
- };
-
- // each property in the object can have a different schema and options so we need to process
- // asynchronously and wait for all to complete
-
- // wrap into waterfall functions
- var propertyFunctions = [];
- for (var propertyId in properties)
- {
- var itemData = null;
- if (_this.data)
- {
- itemData = _this.data[propertyId];
- }
-
- var pf = (function(propertyId, itemData, extraDataProperties)
- {
- return function(callback)
- {
- // only allow this if we have data, otherwise we end up with circular reference
- _this.resolvePropertySchemaOptions(propertyId, function(schema, options, circular) {
-
- // we only allow addition if the resolved schema isn't circularly referenced
- // or the schema is optional
- if (circular)
- {
- return Alpaca.throwErrorWithCallback("Circular reference detected for schema: " + schema, _this.errorCallback);
- }
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for property: " + propertyId);
- }
-
- _this.createItem(propertyId, schema, options, itemData, null, function(addedItemControl) {
-
- items.push(addedItemControl);
-
- // remove from extraDataProperties helper
- delete extraDataProperties[propertyId];
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
- });
- });
- };
-
- })(propertyId, itemData, extraDataProperties);
-
- propertyFunctions.push(pf);
- }
-
- Alpaca.series(propertyFunctions, function(err) {
- cf();
- });
- },
-
- /**
- * Creates an sub-item for this object.
- *
- * The postRenderCallback method is called upon completion.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} postRenderCallback called once the item has been added
- */
- createItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, postRenderCallback)
- {
- var self = this;
-
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render" : function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // add the property Id
- fieldControl.propertyId = propertyId;
- // setup item path
- if (self.path !== "/") {
- fieldControl.path = self.path + "/" + propertyId;
- } else {
- fieldControl.path = self.path + propertyId;
- }
- fieldControl.render(null, function() {
- cb();
- });
- },
- "postRender": function(control) {
-
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- },
-
- /**
- * Determines the schema and options to utilize for sub-objects within this object.
- *
- * @param propertyId
- * @param callback
- */
- resolvePropertySchemaOptions: function(propertyId, callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedPropertySchema, resolvedPropertyOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedPropertyOptions.readonly = true;
- }
-
- callback(resolvedPropertySchema, resolvedPropertyOptions, circular);
- };
-
- var propertySchema = null;
- if (_this.schema && _this.schema.properties && _this.schema.properties[propertyId]) {
- propertySchema = _this.schema.properties[propertyId];
- }
- var propertyOptions = {};
- if (_this.options && _this.options.fields && _this.options.fields[propertyId]) {
- propertyOptions = _this.options.fields[propertyId];
- }
-
- // handle $ref
- if (propertySchema && propertySchema["$ref"])
- {
- var referenceId = propertySchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalPropertySchema = propertySchema;
- var originalPropertyOptions = propertyOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(propertySchema, propertyOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedPropertySchema = {};
- if (originalPropertySchema) {
- Alpaca.mergeObject(resolvedPropertySchema, originalPropertySchema);
- }
- if (propertySchema)
- {
- Alpaca.mergeObject(resolvedPropertySchema, propertySchema);
- }
- // keep original id
- if (originalPropertySchema && originalPropertySchema.id) {
- resolvedPropertySchema.id = originalPropertySchema.id;
- }
- //delete resolvedPropertySchema.id;
-
- var resolvedPropertyOptions = {};
- if (originalPropertyOptions) {
- Alpaca.mergeObject(resolvedPropertyOptions, originalPropertyOptions);
- }
- if (propertyOptions)
- {
- Alpaca.mergeObject(resolvedPropertyOptions, propertyOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedPropertySchema, resolvedPropertyOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(propertySchema, propertyOptions);
- });
- }
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- var f = function(i)
- {
- if (i === model.items.length)
- {
- // done
- callback();
- return;
- }
-
- var item = model.items[i];
-
- var propertyId = item.propertyId;
-
- // HANDLE PROPERTY DEPENDENCIES (IF THE PROPERTY HAS THEM)
-
- // if this property has dependencies, show or hide this added item right away
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- // if this property has dependencies, bind update handlers to dependent fields
- self.bindDependencyFieldUpdateEvent(propertyId);
-
- // if this property has dependencies, trigger those to ensure it is in the right state
- self.refreshDependentFieldStates(propertyId);
-
- f(i+1);
- };
- f(0);
- });
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxProperties();
- valInfo["tooManyProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyProperties"), [this.schema.maxProperties]),
- "status": status
- };
-
- status = this._validateMinProperties();
- valInfo["tooFewProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.minProperties]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyProperties"]["status"] && valInfo["tooFewProperties"]["status"];
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMaxProperties: function()
- {
- if (typeof(this.schema["maxProperties"]) == "undefined")
- {
- return true;
- }
-
- var maxProperties = this.schema["maxProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount <= maxProperties;
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMinProperties: function()
- {
- if (typeof(this.schema["minProperties"]) == "undefined")
- {
- return true;
- }
-
- var minProperties = this.schema["minProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount >= minProperties;
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DEPENDENCIES
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Shows or hides a property's field based on how its dependencies evaluate.
- * If a property doesn't have dependencies, this no-ops.
- *
- * @param propertyId
- */
- showOrHidePropertyBasedOnDependencies: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var valid = this.determineAllDependenciesValid(propertyId);
- if (valid)
- {
- item.show();
- item.onDependentReveal();
- }
- else
- {
- item.hide();
- item.onDependentConceal();
- }
-
- item.getFieldEl().trigger("fieldupdate");
- },
-
- /**
- * Determines whether the dependencies for a property pass.
- *
- * @param propertyId
- */
- determineAllDependenciesValid: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so yes, we pass
- return true;
- }
-
- var valid = true;
- if (Alpaca.isString(itemDependencies))
- {
- valid = self.determineSingleDependencyValid(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- valid = valid && self.determineSingleDependencyValid(propertyId, value);
- });
- }
-
- return valid;
- },
-
- /**
- * Binds field updates to any field dependencies.
- *
- * @param propertyId
- */
- bindDependencyFieldUpdateEvent: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var bindEvent = function(propertyId, dependencyPropertyId)
- {
- // dependencyPropertyId is the identifier for the property that the field "propertyId" is dependent on
-
- var dependentField = Alpaca.resolveField(self, dependencyPropertyId);
- if (dependentField)
- {
- dependentField.getFieldEl().bind("fieldupdate", (function(propertyField, dependencyField, propertyId, dependencyPropertyId) {
-
- return function(event)
- {
- // the property "dependencyPropertyId" changed and affects target property ("propertyId")
-
- // update UI state for target property
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- propertyField.getFieldEl().trigger("fieldupdate");
- };
-
- })(item, dependentField, propertyId, dependencyPropertyId));
-
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- bindEvent(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- bindEvent(propertyId, value);
- });
- }
- },
-
- refreshDependentFieldStates: function(propertyId)
- {
- var self = this;
-
- var propertyField = this.childrenByPropertyId[propertyId];
- if (!propertyField)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = propertyField.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var triggerFieldUpdateForProperty = function(otherPropertyId)
- {
- var dependentField = Alpaca.resolveField(self, otherPropertyId);
- if (dependentField)
- {
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- triggerFieldUpdateForProperty(itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- triggerFieldUpdateForProperty(value);
- });
- }
- },
-
- /**
- * Checks whether a single property's dependency is satisfied or not.
- *
- * In order to be valid, the property's dependency must exist (JSON schema) and optionally must satisfy
- * any dependency options (value matches using an AND). Finally, the dependency field must be showing.
- *
- * @param {Object} propertyId Field property id.
- * @param {Object} dependentOnPropertyId Property id of the dependency field.
- *
- * @returns {Boolean} True if all dependencies have been satisfied and the field needs to be shown,
- * false otherwise.
- */
- determineSingleDependencyValid: function(propertyId, dependentOnPropertyId)
- {
- var self = this;
-
- // checks to see if the referenced "dependent-on" property has a value
- // basic JSON-schema supports this (if it has ANY value, it is considered valid
- // special consideration for boolean false
- var dependentOnField = Alpaca.resolveField(self, dependentOnPropertyId);
- if (!dependentOnField)
- {
- // no dependent-on field found, return false
- return false;
- }
-
- var dependentOnData = dependentOnField.data;
-
- // assume it isn't valid
- var valid = false;
-
- // go one of two directions depending on whether we have conditional dependencies or not
- var conditionalDependencies = this.childrenByPropertyId[propertyId].options.dependencies;
- if (!conditionalDependencies || conditionalDependencies.length === 0)
- {
- //
- // BASIC DEPENENDENCY CHECKING (CORE JSON SCHEMA)
- //
-
- // special case: if the field is a boolean field and we have no conditional dependency checking,
- // then we set valid = false if the field data is a boolean false
- if (dependentOnField.getType() === "boolean" && !this.childrenByPropertyId[propertyId].options.dependencies && !dependentOnData)
- {
- valid = false;
- }
- else
- {
- valid = !Alpaca.isValEmpty(dependentOnField.data);
- }
- }
- else
- {
- //
- // CONDITIONAL DEPENDENCY CHECKING (ALPACA EXTENSION VIA OPTIONS)
- //
-
- // Alpaca extends JSON schema by allowing dependencies to trigger only for specific values on the
- // dependent fields. If options are specified to define this, we walk through and perform an
- // AND operation across any fields
-
- // do some data sanity cleanup
- if (dependentOnField.getType() === "boolean" && !dependentOnData) {
- dependentOnData = false;
- }
-
- var conditionalData = conditionalDependencies[dependentOnPropertyId];
-
- // if the option is a function, then evaluate the function to determine whether to show
- // the function evaluates regardless of whether the schema-based fallback determined we should show
- if (!Alpaca.isEmpty(conditionalData) && Alpaca.isFunction(conditionalData))
- {
- valid = conditionalData.call(this, dependentOnData);
- }
- else
- {
- // assume true
- valid = true;
-
- // the conditional data is an array of values
- if (Alpaca.isArray(conditionalData)) {
-
- // check array value
- //if (conditionalDependencies[dependentOnPropertyId] && $.inArray(dependentOnData, conditionalDependencies[dependentOnPropertyId]) == -1)
- if (!Alpaca.anyEquality(dependentOnData, conditionalData))
- {
- valid = false;
- }
- }
- else
- {
- // check object value
- if (!Alpaca.isEmpty(conditionalData) && !Alpaca.anyEquality(conditionalData, dependentOnData))
- {
- valid = false;
- }
- }
- }
- }
-
- //
- // NESTED HIDDENS DEPENDENCY HIDES (ALPACA EXTENSION)
- //
-
- // final check: only set valid if the dependentOnPropertyId is showing
- if (dependentOnField && dependentOnField.isHidden())
- {
- valid = false;
- }
-
- return valid;
- },
-
- /**
- * Gets child index.
- *
- * @param {Object} propertyId Child field property ID.
- */
- getIndex: function(propertyId)
- {
- if (Alpaca.isEmpty(propertyId)) {
- return -1;
- }
- for (var i = 0; i < this.children.length; i++) {
- var pid = this.children[i].propertyId;
- if (pid == propertyId) { // jshint ignore:line
- return i;
- }
- }
- return -1;
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Adds an item to the object.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} callback called once the item has been added
- */
- addItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, callback)
- {
- var self = this;
-
- this.createItem(propertyId, itemSchema, itemOptions, itemData, insertAfterId, function(child) {
-
- var index = null;
- if (insertAfterId && self.childrenById[insertAfterId])
- {
- for (var z = 0; z < self.children.length; z++)
- {
- if (self.children[z].getId() == insertAfterId)
- {
- index = z;
- break;
- }
- }
- }
-
- // register the child
- self.registerChild(child, ((index != null) ? index + 1 : null));
-
- // insert into dom
- if (!index)
- {
- // insert first into container
- $(self.container).append(child.getFieldEl());
- }
- else
- {
- // insert at a specific index
- var existingElement = self.getContainerEl().children("[data-alpaca-container-item-index='" + index + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(child.getFieldEl());
- }
- }
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- //self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState(true, function() {
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
-
- });
- });
- },
-
- /**
- * Removes an item from the object.
- *
- * @param propertyId
- * @param callback
- */
- removeItem: function(propertyId, callback)
- {
- var self = this;
-
- this.children = $.grep(this.children, function(val, index) {
- return (val.getId() != propertyId);
- });
-
- var childField = this.childrenById[propertyId];
-
- delete this.childrenById[propertyId];
- if (childField.propertyId)
- {
- delete this.childrenByPropertyId[childField.propertyId];
- }
-
- childField.destroy();
-
- this.refreshValidationState(true, function() {
-
- // trigger update handler
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // WIZARD
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Wraps the current object into a wizard container and wires up the navigation and buttons so that
- * wizard elements flip nicely.
- */
- wizard: function()
- {
- var self = this;
-
- // config-driven
- var stepDescriptors = this.wizardConfigs.steps;
- if (!stepDescriptors)
- {
- stepDescriptors = [];
- }
- var wizardTitle = this.wizardConfigs.title;
- var wizardDescription = this.wizardConfigs.description;
- var buttonDescriptors = this.wizardConfigs.buttons;
- if (!buttonDescriptors)
- {
- buttonDescriptors = {};
- }
- if (!buttonDescriptors["previous"])
- {
- buttonDescriptors["previous"] = {}
- }
- if (!buttonDescriptors["previous"].title)
- {
- buttonDescriptors["previous"].title = "Previous";
- }
- if (!buttonDescriptors["previous"].align)
- {
- buttonDescriptors["previous"].align = "left";
- }
- if (!buttonDescriptors["previous"].type)
- {
- buttonDescriptors["previous"].type = "button";
- }
- if (!buttonDescriptors["next"])
- {
- buttonDescriptors["next"] = {}
- }
- if (!buttonDescriptors["next"].title)
- {
- buttonDescriptors["next"].title = "Next";
- }
- if (!buttonDescriptors["next"].align)
- {
- buttonDescriptors["next"].align = "right";
- }
- if (!buttonDescriptors["next"].type)
- {
- buttonDescriptors["next"].type = "button";
- }
-
- if (!this.wizardConfigs.hideSubmitButton)
- {
- if (!buttonDescriptors["submit"]) {
- buttonDescriptors["submit"] = {}
- }
- if (!buttonDescriptors["submit"].title) {
- buttonDescriptors["submit"].title = "Submit";
- }
- if (!buttonDescriptors["submit"].align) {
- buttonDescriptors["submit"].align = "right";
- }
- if (!buttonDescriptors["submit"].type) {
- buttonDescriptors["submit"].type = "button";
- }
- }
-
- for (var buttonKey in buttonDescriptors)
- {
- if (!buttonDescriptors[buttonKey].type)
- {
- buttonDescriptors[buttonKey].type = "button";
- }
- }
- var showSteps = this.wizardConfigs.showSteps;
- if (typeof(showSteps) == "undefined")
- {
- showSteps = true;
- }
- var showProgressBar = this.wizardConfigs.showProgressBar;
- var performValidation = this.wizardConfigs.validation;
- if (typeof(performValidation) == "undefined")
- {
- performValidation = true;
- }
-
- // DOM-driven configuration
- var wizardTitle = $(this.field).attr("data-alpaca-wizard-title");
- var wizardDescription = $(this.field).attr("data-alpaca-wizard-description");
- var _wizardValidation = $(this.field).attr("data-alpaca-wizard-validation");
- if (typeof(_wizardValidation) != "undefined")
- {
- performValidation = _wizardValidation ? true : false;
- }
- var _wizardShowSteps = $(this.field).attr("data-alpaca-wizard-show-steps");
- if (typeof(_wizardShowSteps) != "undefined")
- {
- showSteps = _wizardShowSteps ? true : false;
- }
- var _wizardShowProgressBar = $(this.field).attr("data-alpaca-wizard-show-progress-bar");
- if (typeof(_wizardShowProgressBar) != "undefined")
- {
- showProgressBar = _wizardShowProgressBar ? true : false;
- }
-
- // find all of the steps
- var stepEls = $(this.field).find("[data-alpaca-wizard-role='step']");
-
- // DOM-driven configuration of step descriptors
- if (stepDescriptors.length == 0)
- {
- stepEls.each(function(i) {
-
- var stepDescriptor = {};
-
- var stepTitle = $(this).attr("data-alpaca-wizard-step-title");
- if (typeof(stepTitle) != "undefined")
- {
- stepDescriptor.title = stepTitle;
- }
- if (!stepDescriptor.title)
- {
- stepDescriptor.title = "Step " + i;
- }
-
- var stepDescription = $(this).attr("data-alpaca-wizard-step-description");
- if (typeof(stepDescription) != "undefined")
- {
- stepDescriptor.description = stepDescription;
- }
- if (!stepDescriptor.description)
- {
- stepDescriptor.description = "Step " + i;
- }
-
- stepDescriptors.push(stepDescriptor);
- });
- }
-
- // assume something for progress bar if not specified
- if (typeof(showProgressBar) == "undefined")
- {
- if (stepDescriptors.length > 1)
- {
- showProgressBar = true;
- }
- }
-
-
- // model for use in rendering the wizard
- var model = {};
- model.wizardTitle = wizardTitle;
- model.wizardDescription = wizardDescription;
- model.showSteps = showSteps;
- model.performValidation = performValidation;
- model.steps = stepDescriptors;
- model.buttons = buttonDescriptors;
- model.schema = self.schema;
- model.options = self.options;
- model.data = self.data;
- model.showProgressBar = showProgressBar;
- model.markAllStepsVisited = this.wizardConfigs.markAllStepsVisited;
- model.view = self.view;
-
- // render the actual wizard
- var wizardTemplateDescriptor = self.view.getTemplateDescriptor("wizard", self);
- if (wizardTemplateDescriptor)
- {
- var wizardEl = Alpaca.tmpl(wizardTemplateDescriptor, model);
-
- $(self.field).append(wizardEl);
-
- var wizardNav = $(wizardEl).find(".alpaca-wizard-nav");
- var wizardSteps = $(wizardEl).find(".alpaca-wizard-steps");
- var wizardButtons = $(wizardEl).find(".alpaca-wizard-buttons");
- var wizardProgressBar = $(wizardEl).find(".alpaca-wizard-progress-bar");
-
- // move steps into place
- $(wizardSteps).append(stepEls);
-
- (function(wizardNav, wizardSteps, wizardButtons, model) {
-
- var currentIndex = 0;
-
- var previousButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='previous']");
- var nextButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='next']");
- var submitButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='submit']");
-
- // snap into place a little controller to work the buttons
- // assume the first step
- var refreshSteps = function()
- {
- // NAV
- if (model.showSteps)
- {
- if (!model.visits)
- {
- model.visits = {};
- }
-
- // optionally mark all steps as visited
- if (model.markAllStepsVisited)
- {
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- for (var g = 0; g < stepElements.length; g++)
- {
- model.visits[g] = true;
- }
- }
-
- // mark current step as visited
- model.visits[currentIndex] = true;
-
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- $(stepElements).removeClass("disabled");
- $(stepElements).removeClass("completed");
- $(stepElements).removeClass("active");
- $(stepElements).removeClass("visited");
- for (var g = 0; g < stepElements.length; g++)
- {
- if (g < currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("completed");
- }
- else if (g === currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("active");
- }
- else
- {
- if (model.visits && model.visits[g])
- {
- // do not mark disabled for this case
- }
- else
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("disabled");
- }
-
- }
-
- if (model.visits && model.visits[g])
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("visited");
- }
- }
- }
-
- // PROGRESS BAR
- if (model.showProgressBar)
- {
- var valueNow = currentIndex + 1;
- var valueMax = model.steps.length + 1;
- var width = parseInt(((valueNow / valueMax) * 100), 10) + "%";
-
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuemax", valueMax);
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuenow", valueNow);
- $(wizardProgressBar).find(".progress-bar").css("width", width);
- }
-
-
- // BUTTONS
-
- // hide everything
- previousButtonEl.hide();
- nextButtonEl.hide();
- submitButtonEl.hide();
-
- // simple case
- if (model.steps.length == 1)
- {
- submitButtonEl.show();
- }
- else if (model.steps.length > 1)
- {
- if (currentIndex > 0)
- {
- previousButtonEl.show();
- }
-
- nextButtonEl.show();
-
- if (currentIndex == 0)
- {
- nextButtonEl.show();
- }
- else if (currentIndex == model.steps.length - 1)
- {
- nextButtonEl.hide();
- submitButtonEl.show();
- }
- }
-
- // hide all steps
- $(wizardSteps).find("[data-alpaca-wizard-role='step']").hide();
- $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]).show();
-
- };
-
- var assertValidation = function(buttonId, callback)
- {
- if (!model.performValidation)
- {
- callback(true);
- return;
- }
-
- // collect all of the fields on the current step
- var fields = [];
-
- var currentStepEl = $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]);
- $(currentStepEl).find(".alpaca-field").each(function() {
- var fieldId = $(this).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var field = self.childrenById[fieldId];
- if (field)
- {
- fields.push(field);
- }
- }
- });
-
- // wrap into validation functions
- var fns = [];
- for (var i = 0; i < fields.length; i++)
- {
- fns.push(function(field) {
- return function(cb)
- {
- field.refreshValidationState(true, function() {
- cb();
- });
- }
- }(fields[i]));
- }
-
- // run all validations
- Alpaca.series(fns, function() {
-
- var valid = true;
- for (var i = 0; i < fields.length; i++)
- {
- valid = valid && fields[i].isValid(true);
- }
-
- // custom validation function?
- var b = model.buttons[buttonId];
- if (b && b.validate)
- {
- b.validate.call(self, function(_valid) {
- valid = valid && _valid;
- callback(valid);
- });
- }
- else
- {
- callback(valid);
- }
- });
- };
-
- $(previousButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex >= 1)
- {
- //assertValidation("previous", function(valid) {
-
- //if (valid)
- //{
- var b = model.buttons["previous"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex--;
-
- refreshSteps();
- //}
- //});
- }
- });
-
- $(nextButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex + 1 <= model.steps.length - 1)
- {
- assertValidation("next", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["next"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex++;
-
- refreshSteps();
- }
- });
- }
- });
-
- $(submitButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex === model.steps.length - 1)
- {
- assertValidation("submit", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["submit"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- else
- {
- // are we in a form?
- if (self.form)
- {
- self.form.submit();
- }
- }
- }
- }
- });
- }
- });
-
- // all custom buttons
- $(wizardButtons).find("[data-alpaca-wizard-button-key]").each(function() {
- var key = $(this).attr("data-alpaca-wizard-button-key");
- if (key != "submit" && key != "next" && key != "previous") { // standard buttons have different behavior
- var b = model.buttons[key];
- if (b && b.click) {
- $(this).click(function (b) {
- return function (e) {
- b.click.call(self, e);
- };
- }(b));
- }
- }
- });
-
- $(wizardNav).find("[data-alpaca-wizard-step-index]").click(function(e) {
- e.preventDefault();
-
- var navIndex = $(this).attr("data-alpaca-wizard-step-index");
- if (navIndex)
- {
- navIndex = parseInt(navIndex, 10);
-
- if (navIndex == currentIndex || (model.visits && model.visits[navIndex]))
- {
- // if we're going backwards, then we do not run validation
- if (navIndex < currentIndex)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- else if (navIndex > currentIndex)
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- });
- }
- else
- {
- // current item should not be clickable
- }
- }
- }
- });
-
- self.on("moveToStep", function(event) {
-
- var index = event.index;
- var skipValidation = event.skipValidation;
-
- if ((typeof(index) !== "undefined") && index <= model.steps.length - 1)
- {
- if (skipValidation)
- {
- currentIndex = index;
- refreshSteps();
- }
- else
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = index;
-
- refreshSteps();
- }
- });
- }
- }
- });
-
- self.on("advanceOrSubmit", function(event) {
-
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- if (currentIndex === model.steps.length - 1)
- {
- $(submitButtonEl).click();
- }
- else
- {
- $(nextButtonEl).click();
- }
- }
- });
- });
-
-
- refreshSteps();
-
- }(wizardNav, wizardSteps, wizardButtons, model));
- }
- },
-
- /**
- * Renders a configuration-based wizard without a layout template.
- */
- autoWizard: function()
- {
- var stepBindings = this.wizardConfigs.bindings;
- if (!stepBindings)
- {
- stepBindings = {};
- }
-
- for (var propertyId in this.childrenByPropertyId)
- {
- if (!stepBindings.hasOwnProperty(propertyId))
- {
- stepBindings[propertyId] = 1;
- }
- }
-
- // should we create steps?
- var createSteps = true;
- if ($(this.field).find("[data-alpaca-wizard-role='step']").length > 0)
- {
- // already there
- createSteps = false;
- }
-
- var step = 1;
- var col = [];
- do
- {
- // collect fields in this step
- col = [];
- for (var propertyId in stepBindings)
- {
- if (stepBindings[propertyId] == step)
- {
- if (this.childrenByPropertyId && this.childrenByPropertyId[propertyId])
- {
- col.push(this.childrenByPropertyId[propertyId].field);
- }
- }
- }
-
- if (col.length > 0)
- {
- var stepEl = null;
- if (createSteps)
- {
- stepEl = $('');
- $(this.field).append(stepEl);
- }
- else
- {
- stepEl = $($(this.field).find("[data-alpaca-wizard-role='step']")[step-1]);
- }
-
- // move elements in
- for (var i = 0; i < col.length; i++)
- {
- $(stepEl).append(col[i]);
- }
-
- step++;
- }
- }
- while (col.length > 0);
-
- // now run the normal wizard
- this.wizard();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "object";
- },
-
- /**
- * Moves a field.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to which the child should be moved
- * @param [Boolean] animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + sourceIndex + "']");
- var targetContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + targetIndex + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find("[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find("[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- if (animate)
- {
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, 500, function() {
- onComplete();
- });
- }
- else
- {
- onComplete();
- }
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Object Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Object field for containing other fields";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "properties": {
- "title": "Properties",
- "description": "List of child properties.",
- "type": "object"
- },
- "maxProperties": {
- "type": "number",
- "title": "Maximum Number Properties",
- "description": "The maximum number of properties that this object is allowed to have"
- },
- "minProperties": {
- "type": "number",
- "title": "Minimum Number of Properties",
- "description": "The minimum number of properties that this object is required to have"
- }
- }
- };
-
- var fieldsProperties = properties.properties.properties;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfSchema();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = Alpaca.merge(this.base(), {
- "properties": {
- }
- });
-
- var properties = {
- "properties": {
- "fields": {
- "title": "Field Options",
- "description": "List of options for child fields.",
- "type": "object"
- }
- }
- };
-
- var fieldsProperties = properties.properties.fields;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfOptions();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(schemaOfOptions, properties);
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "tooManyProperties": "The maximum number of properties ({0}) has been exceeded.",
- "tooFewProperties": "There are not enough properties ({0} are required)"
- });
-
- Alpaca.registerFieldClass("object", Alpaca.Fields.ObjectField);
- Alpaca.registerDefaultSchemaFieldMapping("object", "object");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AnyField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.AnyField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "any";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.control.disabled = true;
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.control.disabled = false;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- this.control.focus();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "any";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Any Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Any field.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("any", Alpaca.Fields.AnyField);
- Alpaca.registerDefaultSchemaFieldMapping("any", "any");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.HiddenField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ControlField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "hidden";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value)) {
- this.getControlEl().val("");
- } else {
- this.getControlEl().val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Hidden";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Field for a hidden HTML input";
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("hidden", Alpaca.Fields.HiddenField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AddressField = Alpaca.Fields.ObjectField.extend(
- /**
- * @lends Alpaca.Fields.AddressField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.ObjectField#getFieldType
- */
- getFieldType: function() {
- return "address";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.data === undefined) {
- this.data = {
- street: ['', '']
- };
- }
-
- this.schema = {
- "title": "Home Address",
- "type": "object",
- "properties": {
- "street": {
- "title": "Street",
- "type": "array",
- "items": {
- "type": "string",
- "maxLength": 30,
- "minItems": 0,
- "maxItems": 3
- }
- },
- "city": {
- "title": "City",
- "type": "string"
- },
- "state": {
- "title": "State",
- "type": "string",
- "enum": ["AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY"]
- },
- "zip": {
- "title": "Zip Code",
- "type": "string",
- "pattern": /^(\d{5}(-\d{4})?)?$/
- }
- }
- };
- Alpaca.merge(this.options, {
- "fields": {
- "zip": {
- "maskString": "99999",
- "size": 5
- },
- "state": {
- "optionLabels": ["ALABAMA", "ALASKA", "AMERICANSAMOA", "ARIZONA", "ARKANSAS", "CALIFORNIA", "COLORADO", "CONNECTICUT", "DELAWARE", "DISTRICTOFCOLUMBIA", "FEDERATEDSTATESOFMICRONESIA", "FLORIDA", "GEORGIA", "GUAM", "HAWAII", "IDAHO", "ILLINOIS", "INDIANA", "IOWA", "KANSAS", "KENTUCKY", "LOUISIANA", "MAINE", "MARSHALLISLANDS", "MARYLAND", "MASSACHUSETTS", "MICHIGAN", "MINNESOTA", "MISSISSIPPI", "MISSOURI", "MONTANA", "NEBRASKA", "NEVADA", "NEWHAMPSHIRE", "NEWJERSEY", "NEWMEXICO", "NEWYORK", "NORTHCAROLINA", "NORTHDAKOTA", "NORTHERNMARIANAISLANDS", "OHIO", "OKLAHOMA", "OREGON", "PALAU", "PENNSYLVANIA", "PUERTORICO", "RHODEISLAND", "SOUTHCAROLINA", "SOUTHDAKOTA", "TENNESSEE", "TEXAS", "UTAH", "VERMONT", "VIRGINISLANDS", "VIRGINIA", "WASHINGTON", "WESTVIRGINIA", "WISCONSIN", "WYOMING"]
- }
- }
- });
-
- if (Alpaca.isEmpty(this.options.addressValidation))
- {
- this.options.addressValidation = true;
- }
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return false;
- },
-
- /**
- * Returns address in a single line string.
- *
- * @returns {String} Address as a single line string.
- */
- getAddress: function()
- {
- var value = this.getValue();
- if (this.view.type === "view")
- {
- value = this.data;
- }
- var address = "";
- if (value)
- {
- if (value.street)
- {
- $.each(value.street, function(index, value) {
- address += value + " ";
- });
- }
- if (value.city)
- {
- address += value.city + " ";
- }
- if (value.state)
- {
- address += value.state + " ";
- }
- if (value.zip)
- {
- address += value.zip;
- }
- }
-
- return address;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
- var container = self.getContainerEl();
-
- // apply additional css
- $(container).addClass("alpaca-addressfield");
-
- if (self.options.addressValidation && !self.isDisplayOnly())
- {
- $('').appendTo(container);
- var mapButton = $(' ').appendTo(container);
- if (mapButton.button)
- {
- mapButton.button({
- text: true
- });
- }
- mapButton.click(function() {
-
- if (google && google.maps)
- {
- var geocoder = new google.maps.Geocoder();
- var address = self.getAddress();
- if (geocoder)
- {
- geocoder.geocode({
- 'address': address
- }, function(results, status)
- {
- if (status === google.maps.GeocoderStatus.OK)
- {
- var mapCanvasId = self.getId() + "-map-canvas";
- if ($('#' + mapCanvasId).length === 0)
- {
- $("").appendTo(self.getFieldEl());
- }
-
- var map = new google.maps.Map(document.getElementById(self.getId() + "-map-canvas"), {
- "zoom": 10,
- "center": results[0].geometry.location,
- "mapTypeId": google.maps.MapTypeId.ROADMAP
- });
-
- var marker = new google.maps.Marker({
- map: map,
- position: results[0].geometry.location
- });
-
- }
- else
- {
- self.displayMessage("Geocoding failed: " + status);
- }
- });
- }
-
- }
- else
- {
- self.displayMessage("Google Map API is not installed.");
- }
- }).wrap('');
-
- if (self.options.showMapOnLoad)
- {
- mapButton.click();
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getType
- */
- getType: function() {
- return "any";
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.ObjectField#getTitle
- */
- getTitle: function() {
- return "Address";
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getDescription
- */
- getDescription: function() {
- return "Standard US Address with Street, City, State and Zip. Also comes with support for Google map.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "validateAddress": {
- "title": "Address Validation",
- "description": "Enable address validation if true",
- "type": "boolean",
- "default": true
- },
- "showMapOnLoad": {
- "title": "Whether to show the map when first loaded",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "validateAddress": {
- "helper": "Address validation if checked",
- "rightLabel": "Enable Google Map for address validation?",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("address", Alpaca.Fields.AddressField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CKEditorField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.CKEditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "ckeditor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- if (!this.data)
- {
- this.data = "";
- }
-
- this.base();
-
- if (typeof(this.options.ckeditor) == "undefined")
- {
- this.options.ckeditor = {};
- }
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // see if we can render CK Editor
- if (!self.isDisplayOnly() && self.control && typeof(CKEDITOR) !== "undefined")
- {
- // use a timeout because CKEditor has some odd timing dependencies
- setTimeout(function() {
-
- self.editor = CKEDITOR.replace($(self.control)[0], self.options.ckeditor);
-
- }, 250);
- }
-
- // if the ckeditor's dom element gets destroyed, make sure we clean up the editor instance
- $(self.control).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.removeAllListeners();
- self.editor.destroy(false);
- self.editor = null;
- }
-
- });
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the plugin instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- }
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- ,
- getTitle: function() {
- return "CK Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Provides an instance of a CK Editor control for use in editing HTML.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "ckeditor": {
- "title": "CK Editor options",
- "description": "Use this entry to provide configuration options to the underlying CKEditor plugin.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "ckeditor": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("ckeditor", Alpaca.Fields.CKEditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ColorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ColorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "color";
- this.inputType = "color";
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "color";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Color Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A color picker for selecting hexadecimal color values";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("color", Alpaca.Fields.ColorField);
- Alpaca.registerDefaultSchemaFieldMapping("color", "color");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CountryField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.CountryField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "country";
- },
-
- /**
- * @see Alpaca.Fields.Field#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize))
- {
- this.options.capitalize = false;
- }
-
- this.schema["enum"] = [];
- this.options.optionLabels = [];
-
- var countriesMap = this.view.getMessage("countries");
- if (countriesMap)
- {
- for (var countryKey in countriesMap)
- {
- this.schema["enum"].push(countryKey);
-
- var label = countriesMap[countryKey];
- if (this.options.capitalize)
- {
- label = label.toUpperCase();
- }
-
- this.options.optionLabels.push(label);
- }
- }
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Country Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of countries keyed by their ISO3 code. The names of the countries are read from the I18N bundle for the current locale.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "capitalize": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("country", Alpaca.Fields.CountryField);
- Alpaca.registerDefaultFormatFieldMapping("country", "country");
-
-})(jQuery);
-
-(function($) {
-
- var round = (function() {
- var strategies = {
- up: Math.ceil,
- down: function(input) { return ~~input; },
- nearest: Math.round
- };
- return function(strategy) {
- return strategies[strategy];
- };
- })();
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CurrencyField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.CurrencyField.prototype
- */
- {
- /**
- * @constructs
- * @augments Alpaca.Fields.TextField
- *
- * @class Currency Control
- *
- * @param {Object} container Field container.
- * @param {Any} data Field data.
- * @param {Object} options Field options.
- * @param {Object} schema Field schema.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(container, data, options, schema, view, connector, errorCallback) {
- options = options || {};
-
- var pfOptionsSchema = this.getSchemaOfPriceFormatOptions().properties;
- for (var i in pfOptionsSchema) {
- var option = pfOptionsSchema[i];
- if (!(i in options)) {
- options[i] = option["default"] || undefined;
- }
- }
-
- if (typeof(data) !== "undefined")
- {
- data = "" + parseFloat(data).toFixed(options.centsLimit);
- }
-
- this.base(container, data, options, schema, view, connector, errorCallback);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "currency";
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- var field = this.getControlEl();
-
- this.base(model, function() {
-
- $(field).priceFormat(self.options);
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function() {
-
- var field = this.getControlEl();
-
- var val = $(field).is('input') ? field.val() : field.hmtl();
- if (this.options.unmask || this.options.round !== "none") {
- var unmasked = function() {
- var result = '';
- for (var i in val) {
- var cur = val[i];
- if (!isNaN(cur)) {
- result += cur;
- } else if (cur === this.options.centsSeparator) {
- result += '.';
- }
- }
- return parseFloat(result);
- }.bind(this)();
- if (this.options.round !== "none") {
- unmasked = round(this.options.round)(unmasked);
- if (!this.options.unmask) {
- var result = [];
- var unmaskedString = "" + unmasked;
- for (var i = 0, u = 0; i < val.length; i++) {
- if (!isNaN(val[i])) {
- result.push(unmaskedString[u++] || 0);
- } else {
- result.push(val[i]);
- }
- }
- return result.join('');
- }
- }
- return unmasked;
- } else {
- return val;
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Currency Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides an automatically formatted and configurable input for entering currency amounts.";
- },
-
- getSchemaOfPriceFormatOptions: function() {
- return {
- "properties": {
- "allowNegative": {
- "title": "Allow Negative",
- "description": "Determines if negative numbers are allowed.",
- "type": "boolean",
- "default": false
- },
- "centsLimit": {
- "title": "Cents Limit",
- "description": "The limit of fractional digits.",
- "type": "number",
- "default": 2,
- "minimum": 0
- },
- "centsSeparator": {
- "title": "Cents Separator",
- "description": "The separator between whole and fractional amounts.",
- "type": "text",
- "default": "."
- },
- "clearPrefix": {
- "title": "Clear Prefix",
- "description": "Determines if the prefix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "clearSuffix": {
- "title": "Clear Suffix",
- "description": "Determines if the suffix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "insertPlusSign": {
- "title": "Plus Sign",
- "description": "Determines if a plus sign should be inserted for positive values.",
- "type": "boolean",
- "default": false
- },
- "limit": {
- "title": "Limit",
- "description": "A limit of the length of the field.",
- "type": "number",
- "default": undefined,
- "minimum": 0
- },
- "prefix": {
- "title": "Prefix",
- "description": "The prefix if any for the field.",
- "type": "text",
- "default": "$"
- },
- "round": {
- "title": "Round",
- "description": "Determines if the field is rounded. (Rounding is done when getValue is called and is not reflected in the UI)",
- "type": "string",
- "enum": [ "up", "down", "nearest", "none" ],
- "default": "none"
- },
- "suffix": {
- "title": "Suffix",
- "description": "The suffix if any for the field.",
- "type": "text",
- "default": ""
- },
- "thousandsSeparator": {
- "title": "Thousands Separator",
- "description": "The separator between thousands.",
- "type": "string",
- "default": ","
- },
- "unmask": {
- "title": "Unmask",
- "description": "If true then the resulting value for this field will be unmasked. That is, the resulting value will be a float instead of a string (with the prefix, suffix, etc. removed).",
- "type": "boolean",
- "default": true
- }
- }
- };
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), this.getSchemaOfPriceFormatOptions());
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "allowNegative": {
- "type": "checkbox"
- },
- "centsLimit": {
- "type": "number"
- },
- "centsSeparator": {
- "type": "text"
- },
- "clearPrefix": {
- "type": "checkbox"
- },
- "clearSuffix": {
- "type": "checkbox"
- },
- "insertPlusSign": {
- "type": "checkbox"
- },
- "limit": {
- "type": "number"
- },
- "prefix": {
- "type": "text"
- },
- "round": {
- "type": "select"
- },
- "suffix": {
- "type": "text"
- },
- "thousandsSeparator": {
- "type": "string"
- },
- "unmask": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("currency", Alpaca.Fields.CurrencyField);
-
-})(jQuery);
-
-(function($) {
-
- // NOTE: this requires bootstrap-datetimepicker.js
- // NOTE: this requires moment.js
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DateField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.DateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "date";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY";
- },
-
- getDefaultExtraFormats: function() {
- return [];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "date";
- //this.inputType = "date";
-
- this.base();
-
- if (!self.options.picker)
- {
- self.options.picker = {};
- }
-
- if (typeof(self.options.picker.useCurrent) === "undefined") {
- self.options.picker.useCurrent = false;
- }
-
- // date format
-
- if (self.options.picker.format) {
- self.options.dateFormat = self.options.picker.format;
- }
- if (!self.options.dateFormat) {
- self.options.dateFormat = self.getDefaultFormat();
- }
- if (!self.options.picker.format) {
- self.options.picker.format = self.options.dateFormat;
- }
-
- // extra formats
- if (!self.options.picker.extraFormats) {
- var extraFormats = self.getDefaultExtraFormats();
- if (extraFormats) {
- self.options.picker.extraFormats = extraFormats;
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#afterRenderControl
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- if (self.view.type !== "display")
- {
- if ($.fn.datetimepicker)
- {
- self.getControlEl().datetimepicker(self.options.picker);
-
- self.picker = self.getControlEl().data("DateTimePicker");
- if (self.picker && self.options.dateFormat)
- {
- self.picker.format(self.options.dateFormat);
- }
- if (self.picker)
- {
- self.options.dateFormat = self.picker.format();
- }
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- getDate: function()
- {
- var self = this;
-
- var date = null;
- try
- {
- if (self.picker)
- {
- date = (self.picker.date() ? self.picker.date()._d: null);
- }
- else
- {
- date = new Date(this.getValue());
- }
- }
- catch (e)
- {
- console.error(e);
- }
-
- return date;
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- date: function()
- {
- return this.getDate();
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- this.refreshValidationState();
- },
-
- isAutoFocusable: function()
- {
- return false;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateDateFormat();
- valInfo["invalidDate"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidDate"), [this.options.dateFormat]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidDate"]["status"];
- },
-
- /**
- * Validates date format.
- *
- * @returns {Boolean} True if it is a valid date, false otherwise.
- */
- _validateDateFormat: function()
- {
- var self = this;
-
- var isValid = true;
-
- if (self.options.dateFormat)
- {
- var value = self.getValue();
- if (value || self.isRequired())
- {
- // collect all formats
- var dateFormats = [];
- dateFormats.push(self.options.dateFormat);
- if (self.options.picker && self.options.picker.extraFormats)
- {
- for (var i = 0; i < self.options.picker.extraFormats.length; i++)
- {
- dateFormats.push(self.options.picker.extraFormats[i]);
- }
- }
-
- for (var i = 0; i < dateFormats.length; i++)
- {
- isValid = isValid || moment(value, self.options.dateFormat, true).isValid();
- }
- }
- }
-
- return isValid;
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- this.base(value);
-
- if (this.picker)
- {
- if (moment(value, self.options.dateFormat, true).isValid())
- {
- this.picker.date(value);
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- return this.base();
- },
-
- destroy: function()
- {
- this.base();
-
- this.picker = null;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Date Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Date Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"date",
- "enum" : ["date"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "dateFormat": {
- "title": "Date Format",
- "description": "Date format (using moment.js format)",
- "type": "string"
- },
- "picker": {
- "title": "DatetimePicker options",
- "description": "Options that are supported by the Bootstrap DateTime Picker.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "dateFormat": {
- "type": "text"
- },
- "picker": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidDate": "Invalid date for format {0}"
- });
- Alpaca.registerFieldClass("date", Alpaca.Fields.DateField);
- Alpaca.registerDefaultFormatFieldMapping("date", "date");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DatetimeField = Alpaca.Fields.DateField.extend(
- /**
- * @lends Alpaca.Fields.DatetimeField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "datetime";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY HH:mm:ss";
- },
-
- getDefaultExtraFormats: function() {
- return [
- "MM/DD/YYYY hh:mm:ss a",
- "MM/DD/YYYY HH:mm",
- "MM/DD/YYYY"
- ];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "datetime";
- //this.inputType = "datetime";
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Datetime Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Datetime Field based on Bootstrap DateTime Picker.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("datetime", Alpaca.Fields.DatetimeField);
-
- // "datetime" is legacy (pre v4 schema)
- Alpaca.registerDefaultFormatFieldMapping("datetime", "datetime");
-
- // official v4 uses date-time
- Alpaca.registerDefaultFormatFieldMapping("date-time", "datetime");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EditorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "editor";
- },
-
- setup: function()
- {
- var self = this;
-
- this.base();
-
- if (!self.options.aceTheme)
- {
- self.options.aceTheme = "ace/theme/chrome";
- }
-
- if (!self.options.aceMode)
- {
- self.options.aceMode = "ace/mode/json";
- }
-
- if (typeof(self.options.beautify) == "undefined")
- {
- self.options.beautify = true;
- }
-
- if (self.options.beautify && this.data)
- {
- if (self.options.aceMode === "ace/mode/json")
- {
- if (Alpaca.isObject(this.data))
- {
- // convert to string to format it
- this.data = JSON.stringify(this.data, null, " ");
- }
- else if (Alpaca.isString(this.data))
- {
- // convert to object and then back to string to format it
- this.data = JSON.stringify(JSON.parse(this.data), null, " ");
- }
- }
-
- if (self.options.aceMode === "ace/mode/html")
- {
- if (typeof(html_beautify) !== "undefined")
- {
- this.data = html_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/css")
- {
- if (typeof(css_beautify) !== "undefined")
- {
- this.data = css_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/javascript")
- {
- if (typeof(js_beautify) !== "undefined")
- {
- this.data = js_beautify(this.data);
- }
- }
- }
-
- if (self.options.aceMode === "ace/mode/json")
- {
- if (!this.data || this.data === "{}")
- {
- this.data = "{\n\t\n}";
- }
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // ACE HEIGHT
- var aceHeight = self.options.aceHeight;
- if (aceHeight)
- {
- $(self.control).css("height", aceHeight);
- }
-
- // ACE WIDTH
- var aceWidth = self.options.aceWidth;
- if (!aceWidth) {
- aceWidth = "100%";
- }
- $(self.control).css("width", aceWidth);
- }
-
- // locate where we will insert the editor
- var el = $(self.control)[0];
-
- // ace must be included ahead of time
- if (!ace && window.ace) {
- ace = window.ace;
- }
-
- if (!ace)
- {
- Alpaca.logError("Editor Field is missing the 'ace' Cloud 9 Editor");
- }
- else
- {
- self.editor = ace.edit(el);
- self.editor.setOptions({
- maxLines: Infinity
- });
-
- self.editor.getSession().setUseWrapMode(true);
-
- // theme
- var aceTheme = self.options.aceTheme;
- self.editor.setTheme(aceTheme);
-
- // mode
- var aceMode = self.options.aceMode;
- self.editor.getSession().setMode(aceMode);
-
- self.editor.renderer.setHScrollBarAlwaysVisible(false);
- //this.editor.renderer.setVScrollBarAlwaysVisible(false); // not implemented
- self.editor.setShowPrintMargin(false);
-
- // set data onto editor
- self.editor.setValue(self.data);
- self.editor.clearSelection();
-
- // clear undo session
- self.editor.getSession().getUndoManager().reset();
-
- // FIT-CONTENT the height of the editor to the contents contained within
- if (self.options.aceFitContentHeight)
- {
- var heightUpdateFunction = function() {
-
- var first = false;
- if (self.editor.renderer.lineHeight === 0)
- {
- first = true;
- self.editor.renderer.lineHeight = 16;
- }
-
- // http://stackoverflow.com/questions/11584061/
- var newHeight = self.editor.getSession().getScreenLength() * self.editor.renderer.lineHeight + self.editor.renderer.scrollBar.getWidth();
-
- $(self.control).height(newHeight.toString() + "px");
-
- // This call is required for the editor to fix all of
- // its inner structure for adapting to a change in size
- self.editor.resize();
-
- if (first)
- {
- window.setTimeout(function() {
- self.editor.clearSelection();
- }, 100);
- }
- };
-
- // Set initial size to match initial content
- heightUpdateFunction();
-
- // Whenever a change happens inside the ACE editor, update
- // the size again
- self.editor.getSession().on('change', heightUpdateFunction);
- }
-
- // READONLY
- if (self.schema.readonly)
- {
- self.editor.setReadOnly(true);
- }
-
- // if the editor's dom element gets destroyed, make sure we clean up the editor instance
- // normally, we expect Alpaca fields to be destroyed by the destroy() method but they may also be
- // cleaned-up via the DOM, thus we check here.
- $(el).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.destroy();
- self.editor = null;
- }
-
- });
- }
-
- callback();
- });
-
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the editor instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- },
-
- /**
- * @return the ACE editor instance
- */
- getEditor: function()
- {
- return this.editor;
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var wordCountStatus = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": wordCountStatus ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": wordCountStatus
- };
-
- var editorAnnotationsStatus = this._validateEditorAnnotations();
- valInfo["editorAnnotationsExist"] = {
- "message": editorAnnotationsStatus ? "" : this.view.getMessage("editorAnnotationsExist"),
- "status": editorAnnotationsStatus
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"] && valInfo["editorAnnotationsExist"]["status"];
- },
-
- _validateEditorAnnotations: function()
- {
- if (this.editor)
- {
- var annotations = this.editor.getSession().getAnnotations();
- if (annotations && annotations.length > 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.editor.getValue();
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Force editor to resize to ensure it gets drawn correctly.
- * @override
- */
- onDependentReveal: function()
- {
- if (this.editor)
- {
- this.editor.resize();
- }
- },
-
- /**
- *@see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- if (this.editor)
- {
- if (self.schema.type == "object" && Alpaca.isObject(value))
- {
- // format
- value = JSON.stringify(value, null, " ");
- }
-
- this.editor.setValue(value);
- self.editor.clearSelection();
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var value = null;
-
- if (this.editor)
- {
- value = this.editor.getValue();
- }
-
- // if expected type back is "object", we do the conversion
- if (this.schema.type == "object")
- {
- if (!value)
- {
- value = {};
- }
- else
- {
- value = JSON.parse(value);
- }
- }
-
- return value;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Editor";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "aceTheme": {
- "title": "ACE Editor Theme",
- "description": "Specifies the theme to set onto the editor instance",
- "type": "string",
- "default": "ace/theme/twilight"
- },
- "aceMode": {
- "title": "ACE Editor Mode",
- "description": "Specifies the mode to set onto the editor instance",
- "type": "string",
- "default": "ace/mode/javascript"
- },
- "aceWidth": {
- "title": "ACE Editor Height",
- "description": "Specifies the width of the wrapping div around the editor",
- "type": "string",
- "default": "100%"
- },
- "aceHeight": {
- "title": "ACE Editor Height",
- "description": "Specifies the height of the wrapping div around the editor",
- "type": "string",
- "default": "300px"
- },
- "aceFitContentHeight": {
- "title": "ACE Fit Content Height",
- "description": "Configures the ACE Editor to auto-fit its height to the contents of the editor",
- "type": "boolean",
- "default": false
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "aceTheme": {
- "type": "text"
- },
- "aceMode": {
- "type": "text"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded.",
- "editorAnnotationsExist": "The editor has errors in it that must be corrected"
- });
-
- Alpaca.registerFieldClass("editor", Alpaca.Fields.EditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EmailField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EmailField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "email";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "email";
- this.inputType = "email";
-
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.email;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidEmail");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Email Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Email Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.email;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"email",
- "enum":["email"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidEmail": "Invalid Email address e.g. info@cloudcms.com"
- });
- Alpaca.registerFieldClass("email", Alpaca.Fields.EmailField);
- Alpaca.registerDefaultFormatFieldMapping("email", "email");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.GridField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.GridField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "grid";
- },
-
- setup: function()
- {
- this.base();
-
- if (typeof(this.options.grid) == "undefined")
- {
- this.options.grid = {};
- }
- },
-
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // convert the data array into the grid's expected format
- var gridData = [];
-
- // add in headers
- var headers = [];
- for (var key in self.options.fields)
- {
- var fieldDefinition = self.options.fields[key];
-
- var label = key;
- if (fieldDefinition.label)
- {
- label = fieldDefinition.label;
- }
-
- headers.push(label);
- }
- gridData.push(headers);
-
- for (var i = 0; i < self.data.length; i++)
- {
- var row = [];
- for (var key2 in self.data[i])
- {
- row.push(self.data[i][key2]);
- }
- gridData.push(row);
- }
-
- /*
- // TODO
- var gridData = [
- ["Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
- ["2009", 0, 2941, 4303, 354, 5814],
- ["2010", 5, 2905, 2867, 412, 5284],
- ["2011", 4, 2517, 4822, 552, 6127],
- ["2012", 2, 2422, 5399, 776, 4151]
- ];
- */
-
- var holder = $(self.container).find(".alpaca-container-grid-holder");
-
- var gridConfig = self.options.grid;
- gridConfig.data = gridData;
-
- $(holder).handsontable(gridConfig);
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.ControlField#getType
- */
- getType: function() {
- return "array";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.ControlField#getTitle
- */
- getTitle: function() {
- return "Grid Field";
- },
-
- /**
- * @see Alpaca.ControlField#getDescription
- */
- getDescription: function() {
- return "Renders array items into a grid";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("grid", Alpaca.Fields.GridField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ImageField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ImageField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "image";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Image Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Image Field.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("image", Alpaca.Fields.ImageField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IntegerField = Alpaca.Fields.NumberField.extend(
- /**
- * @lends Alpaca.Fields.IntegerField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.NumberField#getFieldType
- */
- getFieldType: function() {
- return "integer";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseInt(val, 10);
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- if (this.slider)
- {
- this.slider.slider("value", this.getValue());
- }
- },
-
- /**
- * @see Alpaca.Fields.NumberField#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- if (self.options.slider)
- {
- if (!Alpaca.isEmpty(self.schema.maximum) && !Alpaca.isEmpty(self.schema.minimum))
- {
- if (self.control)
- {
- self.control.after('');
-
- self.slider = $('#slider', self.control.parent()).slider({
- value: self.getValue(),
- min: self.schema.minimum,
- max: self.schema.maximum,
- slide: function(event, ui) {
- self.setValue(ui.value);
- self.refreshValidationState();
- }
- });
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Fields.NumberField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateInteger();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotAnInteger"),
- "status": status
- };
-
- return baseStatus;
- },
-
- /**
- * Validates if it is an integer.
- *
- * @returns {Boolean} true if it is an integer
- */
- _validateInteger: function()
- {
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid integer format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.integer, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getType
- */
- getType: function() {
- return "integer";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.NumberField#getTitle
- */
- getTitle: function() {
- return "Integer Field";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getDescription
- */
- getDescription: function() {
- return "Field for integers.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "integer"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "integer"
- },
- "divisibleBy": {
- "title": "Divisible By",
- "description": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "minimum": {
- "helper": "Minimum value of the field.",
- "type": "integer"
- },
- "maximum": {
- "helper": "Maximum value of the field.",
- "type": "integer"
- },
- "divisibleBy": {
- "helper": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "slider": {
- "title": "Slider",
- "description": "Generate jQuery UI slider control with the field if true.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "slider": {
- "rightLabel": "Slider control ?",
- "helper": "Generate slider control if selected.",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAnInteger": "This value is not an integer."
- });
- Alpaca.registerFieldClass("integer", Alpaca.Fields.IntegerField);
- Alpaca.registerDefaultSchemaFieldMapping("integer", "integer");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IPv4Field = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.IPv4Field.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "ipv4";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.ipv4;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"])
- {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidIPv4");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "IP Address Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "IP Address Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : Alpaca.regexps.ipv4;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "enum": ["ip-address"],
- "default":"ip-address",
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidIPv4": "Invalid IPv4 address, e.g. 192.168.0.1"
- });
- Alpaca.registerFieldClass("ipv4", Alpaca.Fields.IPv4Field);
- Alpaca.registerDefaultFormatFieldMapping("ip-address", "ipv4");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.JSONField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.JSONField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "json";
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- setValue: function(value)
- {
- if (Alpaca.isObject(value) || typeof(value) === "object")
- {
- value = JSON.stringify(value, null, 3);
- }
-
- this.base(value);
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (val && Alpaca.isString(val))
- {
- val = JSON.parse(val);
- }
-
- return val;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateJSON();
- valInfo["stringNotAJSON"] = {
- "message": status.status ? "" : this.view.getMessage("stringNotAJSON") +" "+ status.message,
- "status": status.status
- };
-
- return baseStatus && valInfo["stringNotAJSON"]["status"] ;
- },
-
- /**
- * Validates if it is a valid JSON object.
- * @returns {Boolean} true if it is a valid JSON object
- */
- _validateJSON: function()
- {
- var textValue = this.control.val();
-
- // allow null
- if (Alpaca.isValEmpty(textValue))
- {
- return {
- "status" : true
- };
- }
-
- // parse the string
- try
- {
- var obj = JSON.parse(textValue);
-
- // format the string as well
- this.setValue(JSON.stringify(obj, null, 3));
- return {
- "status" : true
- };
- }
- catch(e)
- {
- return {
- "status" : false,
- "message" : e.message
- };
- }
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // Some auto-formatting capabilities
- self.control.bind('keypress', function(e) {
-
- var code = e.keyCode || e.wich;
-
- if (code === 34) {
- self.control.insertAtCaret('"');
- }
- if (code === 123) {
- self.control.insertAtCaret('}');
- }
- if (code === 91) {
- self.control.insertAtCaret(']');
- }
- });
-
- self.control.bind('keypress', 'Ctrl+l', function() {
- self.getFieldEl().removeClass("alpaca-field-focused");
-
- // set class from state
- self.refreshValidationState();
- });
-
- self.control.attr('title','Type Ctrl+L to format and validate the JSON string.');
- }
-
- callback();
-
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "JSON Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Editor for JSON objects with basic validation and formatting.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAJSON": "This value is not a valid JSON string."
- });
-
- Alpaca.registerFieldClass("json", Alpaca.Fields.JSONField);
-
- $.fn.insertAtCaret = function (myValue) {
-
- return this.each(function() {
-
- //IE support
- if (document.selection) {
-
- this.focus();
- sel = document.selection.createRange();
- sel.text = myValue;
- this.focus();
-
- } else if (this.selectionStart || this.selectionStart == '0') { // jshint ignore:line
-
- //MOZILLA / NETSCAPE support
- var startPos = this.selectionStart;
- var endPos = this.selectionEnd;
- var scrollTop = this.scrollTop;
- this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
- this.focus();
- this.selectionStart = startPos /*+ myValue.length*/;
- this.selectionEnd = startPos /*+ myValue.length*/;
- this.scrollTop = scrollTop;
-
- } else {
-
- this.value += myValue;
- this.focus();
- }
- });
- };
-
- /*
- * jQuery Hotkeys Plugin
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- *
- * Based upon the plugin by Tzury Bar Yochay:
- * http://github.com/tzuryby/hotkeys
- *
- * Original idea by:
- * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
- */
- jQuery.hotkeys = {
- version: "0.8",
-
- specialKeys: {
- 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
- 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
- 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
- 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
- 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
- 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
- },
-
- shiftNums: {
- "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
- "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
- ".": ">", "/": "?", "\\": "|"
- }
- };
-
- function keyHandler( handleObj ) {
- // Only care when a possible input has been specified
- if ( typeof handleObj.data !== "string" ) {
- return;
- }
-
- var origHandler = handleObj.handler,
- keys = handleObj.data.toLowerCase().split(" ");
-
- handleObj.handler = function( event ) {
- // Don't fire in text-accepting inputs that we didn't directly bind to
- if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
- event.target.type === "text") ) {
- return;
- }
-
- // Keypress represents characters, not special keys
- var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
- character = String.fromCharCode( event.which ).toLowerCase(),
- key, modif = "", possible = {};
-
- // check combinations (alt|ctrl|shift+anything)
- if ( event.altKey && special !== "alt" ) {
- modif += "alt+";
- }
-
- if ( event.ctrlKey && special !== "ctrl" ) {
- modif += "ctrl+";
- }
-
- // TODO: Need to make sure this works consistently across platforms
- if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
- modif += "meta+";
- }
-
- if ( event.shiftKey && special !== "shift" ) {
- modif += "shift+";
- }
-
- if ( special ) {
- possible[ modif + special ] = true;
-
- } else {
- possible[ modif + character ] = true;
- possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
-
- // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
- if ( modif === "shift+" ) {
- possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
- }
- }
-
- for ( var i = 0, l = keys.length; i < l; i++ ) {
- if ( possible[ keys[i] ] ) {
- return origHandler.apply( this, arguments );
- }
- }
- };
- }
-
- jQuery.each([ "keydown", "keyup", "keypress" ], function() {
- jQuery.event.special[ this ] = { add: keyHandler };
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.LowerCaseField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.LowerCaseField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "lowercase";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var lowerValue = val.toLowerCase();
-
- if (lowerValue != this.getValue()) // jshint ignore:line
- {
- this.base(lowerValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Lowercase Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text field for lowercase text.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("lowercase", Alpaca.Fields.LowerCaseField);
- Alpaca.registerDefaultFormatFieldMapping("lowercase", "lowercase");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.MapField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.MapField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "map";
- },
-
- getType: function()
- {
- return "object"
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- // special handling - data can come in as an object, we convert to array
- if (this.data && Alpaca.isObject(this.data))
- {
- var newData = [];
-
- $.each(this.data, function(key, value) {
- var newValue = Alpaca.copyOf(value);
- newValue["_key"] = key;
- newData.push(newValue);
- });
-
- this.data = newData;
- }
-
- this.base();
-
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // special handling, convert back to object
- var o = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
- if (key)
- {
- delete v["_key"];
- o[key] = v;
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var isValidMapKeysNotEmpty = this._validateMapKeysNotEmpty();
- valInfo["keyMissing"] = {
- "message": isValidMapKeysNotEmpty ? "" : this.view.getMessage("keyMissing"),
- "status": isValidMapKeysNotEmpty
- };
-
- var isValidMapKeysUnique = this._validateMapKeysUnique();
- valInfo["keyNotUnique"] = {
- "message": isValidMapKeysUnique ? "" : this.view.getMessage("keyNotUnique"),
- "status": isValidMapKeysUnique
- };
-
- return baseStatus && valInfo["keyMissing"]["status"] && valInfo["keyNotUnique"]["status"];
- },
-
- /**
- * Validates that key fields are not empty.
- *
- * @returns {Boolean} true if keys are not empty
- */
- _validateMapKeysNotEmpty: function()
- {
- var isValid = true;
-
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (!key)
- {
- isValid = false;
- break;
- }
- }
-
- return isValid;
- },
-
- /**
- * Validates if key fields are unique.
- *
- * @returns {Boolean} true if keys are unique
- */
- _validateMapKeysUnique: function()
- {
- var isValid = true;
-
- var keys = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (keys[key])
- {
- isValid = false;
- }
-
- keys[key] = key;
- }
-
- return isValid;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "Map Field";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Field for objects with key/value pairs that share the same schema for values.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("map", Alpaca.Fields.MapField);
-
- // Additional Registrations
- Alpaca.registerMessages({
- "keyNotUnique": "Keys of map field are not unique.",
- "keyMissing": "Map contains an empty key."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PasswordField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PasswordField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "password";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.password;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPassword");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Password Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Password Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : /^[0-9a-zA-Z\x20-\x7E]*$/;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": this.schema.pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"password",
- "enum":["password"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPassword": "Invalid Password"
- });
- Alpaca.registerFieldClass("password", Alpaca.Fields.PasswordField);
- Alpaca.registerDefaultFormatFieldMapping("password", "password");
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PersonalNameField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PersonalNameField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "personalname";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var upperValue = "";
-
- for ( var i = 0; i < val.length; i++ )
- {
- if ( i === 0 )
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else if (val.charAt(i-1) === ' ' || val.charAt(i-1) === '-' || val.charAt(i-1) === "'")
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else
- {
- upperValue += val.charAt(i);
- }
- }
-
- if (upperValue != this.getValue()) // jshint ignore:line
- {
- this.base(upperValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Personal Name";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text Field for personal name with captical letter for first letter & after hyphen, space or apostrophe.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("personalname", Alpaca.Fields.PersonalNameField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PhoneField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PhoneField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "tel";
- this.inputType = "tel";
-
- this.base();
-
- if (!this.schema.pattern) {
- this.schema.pattern = Alpaca.regexps.phone;
- }
-
- if (Alpaca.isEmpty(this.options.maskString)) {
- this.options.maskString = "(999) 999-9999";
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPhone");
- }
-
- return baseStatus;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "phone";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Phone Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Phone Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.phone;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"phone",
- "enum":["phone"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "maskString": {
- "title": "Field Mask String",
- "description": "Expression for field mask",
- "type": "string",
- "default": "(999) 999-9999"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPhone": "Invalid Phone Number, e.g. (123) 456-9999"
- });
- Alpaca.registerFieldClass("phone", Alpaca.Fields.PhoneField);
- Alpaca.registerDefaultFormatFieldMapping("phone", "phone");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SearchField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.SearchField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "search";
- this.inputType = "search";
-
- this.base();
-
- this.options.attributes.results = 5;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "search";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Search Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A search box field";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("search", Alpaca.Fields.SearchField);
- Alpaca.registerDefaultSchemaFieldMapping("search", "search");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.usHoldings = {};
-
- Alpaca.usHoldings.territories = {
- "American Samoa" : "AS",
- "District Of Columbia" : "DC",
- "Federated States Of Micronesia" : "FM",
- "Guam" : "GU",
- "Marshall Islands" : "MH",
- "Northern Mariana Islands" : "MP",
- "Palau" : "PW",
- "Puerto Rico" : "PR",
- "Virgin Islands" : "VI"
- };
-
- Alpaca.usHoldings.states = {
- "Alabama" : "AL",
- "Alaska" : "AK",
- "Arizona" : "AZ",
- "Arkansas" : "AR",
- "California" : "CA",
- "Colorado" : "CO",
- "Connecticut" : "CT",
- "Delaware" : "DE",
- "Florida" : "FL",
- "Georgia" : "GA",
- "Hawaii" : "HI",
- "Idaho" : "ID",
- "Illinois" : "IL",
- "Indiana" : "IN",
- "Iowa" : "IA",
- "Kansas" : "KS",
- "Kentucky" : "KY",
- "Louisiana" : "LA",
- "Maine" : "ME",
- "Maryland" : "MD",
- "Massachusetts" : "MA",
- "Michigan" : "MI",
- "Minnesota" : "MN",
- "Mississippi" : "MS",
- "Missouri" : "MO",
- "Montana" : "MT",
- "Nebraska" : "NE",
- "Nevada" : "NV",
- "New Hampshire" : "NH",
- "New Jersey" : "NJ",
- "New Mexico" : "NM",
- "New York" : "NY",
- "North Carolina" : "NC",
- "North Dakota" : "ND",
- "Ohio" : "OH",
- "Oklahoma" : "OK",
- "Oregon" : "OR",
- "Pennsylvania" : "PA",
- "Rhode Island" : "RI",
- "South Carolina" : "SC",
- "South Dakota" : "SD",
- "Tennessee" : "TN",
- "Texas" : "TX",
- "Utah" : "UT",
- "Vermont" : "VT",
- "Virginia" : "VA",
- "Washington" : "WA",
- "West Virginia" : "WV",
- "Wisconsin" : "WI",
- "Wyoming" : "WY"
- };
-
- Alpaca.Fields.StateField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.StateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "state";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize)) {
- this.options.capitalize = false;
- }
- if (Alpaca.isUndefined(this.options.includeStates)) {
- this.options.includeStates = true;
- }
- if (Alpaca.isUndefined(this.options.includeTerritories)) {
- this.options.includeTerritories = true;
- }
- if (Alpaca.isUndefined(this.options.format)) {
- this.options.format = "name";
- }
-
- // validate settings
- if (this.options.format === "name" || this.options.format === "code")
- {
- // valid formats
- }
- else
- {
- Alpaca.logError("The configured state format: " + this.options.format + " is not a legal value [name, code]");
-
- // default to name format
- this.options.format = "name";
- }
-
- // configure
- var holdings = Alpaca.retrieveUSHoldings(
- this.options.includeStates,
- this.options.includeTerritories,
- (this.options.format === "code"),
- this.options.capitalize);
-
- this.schema["enum"] = holdings.keys;
- this.options.optionLabels = holdings.values;
-
- this.base();
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "State Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of states and/or territories in the United States, keyed by their two-character code.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "How to represent the state values in the selector",
- "type": "string",
- "default": "name",
- "enum":["name", "code"],
- "readonly": true
- },
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- },
- "includeStates": {
- "title": "Include States",
- "description": "Whether to include the states of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- },
- "includeTerritories": {
- "title": "Include Territories",
- "description": "Whether to include the territories of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- },
- "capitalize": {
- "type": "checkbox"
- },
- "includeStates": {
- "type": "checkbox"
- },
- "includeTerritories": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("state", Alpaca.Fields.StateField);
- Alpaca.registerDefaultFormatFieldMapping("state", "state");
-
- /**
- * Helper function to retrieve the holdings of US states and territories.
- *
- * @param {Boolean} includeStates whether to include US states
- * @param {Boolean} includeTerritories whether to include US territories
- * @param {Boolean} codeValue whether to hand back US holding codes (instead of names)
- * @param {Boolean} capitalize whether to capitalize the values handed back
- *
- * @returns {Object} an object containing "keys" and "values", both of which are arrays.
- */
- Alpaca.retrieveUSHoldings = (function()
- {
- return function(includeStates, includeTerritories, codeValue, capitalize) {
- var res = {
- keys: [],
- values: []
- };
- var opts = $.extend(
- {},
- includeStates ? Alpaca.usHoldings.states : {},
- includeTerritories ? Alpaca.usHoldings.territories : {}
- );
- var sorted = Object.keys(opts);
- sorted.sort();
- for (var i in sorted) {
- var state = sorted[i];
- var key = opts[state];
- var value = codeValue ? key : state;
- if (capitalize) {
- value = value.toUpperCase();
- }
- res.keys.push(key);
- res.values.push(value);
- }
- return res;
- };
- })();
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- /**
- * The table field is used for data representations that consist of an array with objects inside of it. The objects
- * must have a uniform structure. The table field renders a standard HTML table using the table. The individual
- * columns are either editable (in edit mode) or simply displayed in read-only mode.
- */
- Alpaca.Fields.TableField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.TableField.prototype
- */
- {
- setup: function()
- {
- var self = this;
-
- if (!self.options)
- {
- self.options = {};
- }
-
- if (typeof(self.options.animate) === "undefined")
- {
- self.options.animate = false;
- }
-
- this.base();
-
- if (!this.options.items.type)
- {
- this.options.items.type = "tablerow";
- }
-
- // support for either "datatable" or "datatables"
- if (this.options.datatable) {
- this.options.datatables = this.options.datatable;
- }
-
- // assume empty options for datatables
- if (typeof(this.options.datatables) === "undefined")
- {
- this.options.datatables = {
- "paging": false,
- "lengthChange": false,
- "info": false,
- "searching": false,
- "ordering": true
- };
- }
-
- // assume actions column to be shown
- if (typeof(this.options.showActionsColumn) === "undefined")
- {
- this.options.showActionsColumn = true;
-
- if (this.options.readonly)
- {
- this.options.showActionsColumn = false;
- }
-
- if (this.isDisplayOnly())
- {
- this.options.showActionsColumn = false;
- }
- }
- },
-
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "table";
- },
-
- /**
- * The table field uses the "array" container convention to render the DOM. As such, nested objects are wrapped
- * in "field" elements that result in slightly incorrect table structures. Part of the reason for this is that
- * browsers are very fussy when it comes to injection of nested TR or TD partials. Here, we generate most
- * things as DIVs and then do some cleanup in this method to make sure that the table is put togehter in the
- * right way.
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- self.cleanupDomInjections();
-
- // apply styles of underlying "table"
- var table = $(this.container).find("table");
- self.applyStyle("table", table);
-
- // if the DataTables plugin is available, use it
- if (self.options.datatables)
- {
- if ($.fn.DataTable)
- {
- $(this.container).find("table").DataTable(self.options.datatables);
- }
- }
-
- callback();
-
- }.bind(self));
- },
-
- cleanupDomInjections: function()
- {
- /**
- * Takes a DOM element and merges it "up" to the parent element. Data attributes and some classes are
- * copied from DOM element into the parent element. The children of the DOM element are added to the
- * parent and the DOM element is removed.
- *
- * @param mergeElement
- */
- var mergeElementUp = function(mergeElement)
- {
- var mergeElementParent = $(mergeElement).parent();
- var mergeElementChildren = $(mergeElement).children();
-
- // copy merge element classes to parent
- var classNames =$(mergeElement).attr('class').split(/\s+/);
- $.each( classNames, function(index, className){
- if (className === "alpaca-merge-up") {
- // skip
- } else {
- $(mergeElementParent).addClass(className);
- }
- });
-
- // copy attributes to TR
- $.each($(mergeElement)[0].attributes, function() {
- if (this.name && this.name.indexOf("data-") === 0)
- {
- $(mergeElementParent).attr(this.name, this.value);
- }
- });
-
- // replace field with children
- if (mergeElementChildren.length > 0)
- {
- $(mergeElement).replaceWith(mergeElementChildren);
- }
- else
- {
- $(mergeElement).remove();
- }
- };
-
- // find each TR's .alpaca-field and merge up
- this.getFieldEl().find("tr > .alpaca-field").each(function() {
- mergeElementUp(this);
- });
-
- // find each TR's .alpaca-container and merge up
- this.getFieldEl().find("tr > .alpaca-container").each(function() {
- mergeElementUp(this);
- });
-
- // find the action bar and slip a TD around it
- var alpacaArrayActionbar = this.getFieldEl().find("." + Alpaca.MARKER_CLASS_ARRAY_ITEM_ACTIONBAR);
- if (alpacaArrayActionbar.length > 0)
- {
- alpacaArrayActionbar.each(function() {
- var td = $("\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-image"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-radio"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-select"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-text"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-textarea"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-url"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "target=\"" - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTarget)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\""; - return buffer; - } - -function program3(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program5(depth0,data) { - - var stack1, helper; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - return escapeExpression(stack1); - } - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n " - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\n "; - return buffer; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\n "; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program4(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program6(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper, options; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - - return "type=\"submit\""; - } - -function program7(depth0,data) { - - - return "type=\"reset\""; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-actionbar"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } - -function program4(depth0,data) { - - var stack1, helper; - if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { return stack1; } - else { return ''; } - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-item"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper, options; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - - return "readonly=\"readonly\""; - } - -function program3(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "name=\""; - if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "data-" - + escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\"" - + escapeExpression((typeof depth0 === functionType ? depth0.apply(depth0) : depth0)) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n\n "; - stack1 = helpers.each.call(depth0, (depth0 && depth0.checkboxOptions), {hash:{},inverse:self.noop,fn:self.programWithDepth(2, program2, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - return buffer; - } -function program2(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n
- *
- * Alpaca(el, config);
- *
- *
- *
- * The full syntax is:
- *
- *
- *
- * Alpaca(el, {
- * "data" : {Any} field data (optional),
- * "schema": {Object} field schema (optional),
- * "options" : {Object} field options (optional),
- * "view": {Object|String} field view (object or id reference) (optional),
- * "render": {Function} callback function for replacing default rendering method (optional),
- * "postRender": {Function} callback function for post-rendering (optional),
- * "error": {Function} callback function for error handling (optional),
- * "connector": {Alpaca.Connector} connector for retrieving or storing data, schema, options, view and templates. (optional)
- * });
- *
- *
- *
- * @returns {*}
- */
- var Alpaca = function()
- {
- var args = Alpaca.makeArray(arguments);
- if (args.length === 0) {
- // illegal
- return Alpaca.throwDefaultError("You must supply at least one argument. This argument can either be a DOM element against which Alpaca will generate a form or it can be a function name. See http://www.alpacajs.org for more details.");
- }
-
- // element is the first argument (either a string or a DOM element)
- var el = args[0];
- if (el && Alpaca.isString(el)) {
- el = $("#" + el);
- }
-
- // other arguments we may want to figure out
- var data = null;
- var schema = null;
- var options = null;
- var view = null;
- var callback = null;
- var renderedCallback = null;
- var errorCallback = null;
- var connector = null;
- var notTopLevel = false;
- var initialSettings = {};
-
- // if these options are provided, then data, schema, options and source are loaded via connector
- var dataSource = null;
- var schemaSource = null;
- var optionsSource = null;
- var viewSource = null;
-
- // hands back the field instance that is bound directly under the element el
- var findExistingAlpacaBinding = function()
- {
- var existing = null;
-
- var topElements = $(el).find(":first");
- if (topElements.length > 0)
- {
- // does a field binding exist?
- var fieldId = $(topElements[0]).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var _existing = Alpaca.fieldInstances[fieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- else
- {
- // does a form binding exist?
- var formId = $(topElements[0]).attr("data-alpaca-form-id");
- if (formId)
- {
- var subElements = $(topElements[0]).find(":first");
- if (subElements.length > 0)
- {
- var subFieldId = $(subElements[0]).attr("data-alpaca-field-id");
- if (subFieldId)
- {
- var _existing = Alpaca.fieldInstances[subFieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- }
- }
- }
- }
-
- return existing;
- };
-
- var specialFunctionNames = ["get", "exists", "destroy"];
- var isSpecialFunction = (args.length > 1 && Alpaca.isString(args[1]) && (specialFunctionNames.indexOf(args[1]) > -1));
-
- var existing = findExistingAlpacaBinding();
- if (existing || isSpecialFunction)
- {
- if (isSpecialFunction)
- {
- // second argument must be a special function name
- var specialFunctionName = args[1];
- if ("get" === specialFunctionName) {
- return existing;
- }
- else if ("exists" === specialFunctionName) {
- return (existing ? true : false);
- }
- else if ("destroy" === specialFunctionName) {
- existing.destroy();
- return;
- }
-
- return Alpaca.throwDefaultError("Unknown special function: " + specialFunctionName);
- }
-
- return existing;
- }
- else
- {
- var config = null;
-
- // just a dom element, no other args?
- if (args.length === 1)
- {
- // grab the data inside of the element and use that for config
- var jsonString = $(el).text();
-
- config = JSON.parse(jsonString);
- $(el).html("");
- }
- else
- {
- if (Alpaca.isObject(args[1]))
- {
- config = args[1];
- }
- else if (Alpaca.isFunction(args[1]))
- {
- config = args[1]();
- }
- else
- {
- config = {
- "data": args[1]
- };
- }
- }
-
- if (!config)
- {
- return Alpaca.throwDefaultError("Unable to determine Alpaca configuration");
- }
-
- data = config.data;
- schema = config.schema;
- options = config.options;
- view = config.view;
- callback = config.render;
- if (config.callback) {
- callback = config.callback;
- }
- renderedCallback = config.postRender;
- errorCallback = config.error;
- connector = config.connector;
-
- // sources
- dataSource = config.dataSource;
- schemaSource = config.schemaSource;
- optionsSource = config.optionsSource;
- viewSource = config.viewSource;
-
- // other
- if (config.ui) {
- initialSettings["ui"] = config.ui;
- }
- if (config.type) {
- initialSettings["type"] = config.type;
- }
- if (!Alpaca.isEmpty(config.notTopLevel)) {
- notTopLevel = config.notTopLevel;
- }
- }
-
- // if no error callback is provided, we fall back to a browser alert
- if (Alpaca.isEmpty(errorCallback)) {
- errorCallback = Alpaca.defaultErrorCallback;
- }
-
- if (Alpaca.isEmpty(connector)) {
- var ConnectorClass = Alpaca.getConnectorClass("default");
- connector = new ConnectorClass("default");
- }
-
- // For second or deeper level of fields, default loader should be the one to do loadAll
- // since schema, data, options and view should have already been loaded.
- // Unless we want to load individual fields (other than the templates) using the provided
- // loader, this should be good enough. The benefit is saving time on loader format checking.
-
- var loadAllConnector = connector;
-
- if (notTopLevel) {
- var LoadAllConnectorClass = Alpaca.getConnectorClass("default");
- loadAllConnector = new LoadAllConnectorClass("default");
- }
-
- if (!options) {
- options = {};
- }
-
- // resets the hideInitValidationError back to default state after first render
- var _resetInitValidationError = function(field)
- {
- // if this is the top-level alpaca field, then we call for validation state to be recalculated across
- // all child fields
- if (!field.parent)
- {
- // final call to update validation state
- // only do this if we're not supposed to suspend initial validation errors
- if (!field.hideInitValidationError)
- {
- field.refreshValidationState(true);
- }
-
- // force hideInitValidationError to false for field and all children
- if (field.view.type !== 'view')
- {
- Alpaca.fieldApplyFieldAndChildren(field, function(field) {
-
- // set to false after first validation (even if in CREATE mode, we only force init validation error false on first render)
- field.hideInitValidationError = false;
-
- });
- }
- }
- };
-
- // wrap rendered callback to allow for UI treatment (dom focus, etc)
- var _renderedCallback = function(field)
- {
- // if top level, apply a unique observable scope id
- if (!field.parent)
- {
- field.observableScope = Alpaca.generateId();
- }
-
- // if top level and focus has not been specified, then auto-set
- if (Alpaca.isUndefined(options.focus) && !field.parent) {
- options.focus = Alpaca.defaultFocus;
- }
-
- // auto-set the focus?
- if (options && options.focus)
- {
- window.setTimeout(function() {
-
- var doFocus = function(__field)
- {
- __field.suspendBlurFocus = true;
- __field.focus();
- __field.suspendBlurFocus = false;
- };
-
- if (options.focus)
- {
- if (field.isControlField && field.isAutoFocusable())
- {
- // just focus on this one
- doFocus(field);
- }
- else if (field.isContainerField)
- {
- // if focus = true, then focus on the first child control if it is auto-focusable
- // and not read-only
- if (options.focus === true)
- {
- // pick first element in form
- if (field.children && field.children.length > 0)
- {
- for (var z = 0; z < field.children.length; z++)
- {
- if (field.children[z].isControlField)
- {
- if (field.children[z].isAutoFocusable() && !field.children[z].options.readonly)
- {
- doFocus(field.children[z]);
- break;
- }
- }
- }
- }
- }
- else if (typeof(options.focus) === "string")
- {
- // assume it is a path to the child
- var child = field.getControlByPath(options.focus);
- if (child && child.isControlField && child.isAutoFocusable())
- {
- doFocus(child);
- }
- }
- }
-
- _resetInitValidationError(field);
- }
- }, 500);
- }
- else
- {
- _resetInitValidationError(field);
- }
-
- if (renderedCallback)
- {
- renderedCallback(field);
- }
- };
-
- loadAllConnector.loadAll({
- "data": data,
- "schema": schema,
- "options": options,
- "view": view,
- "dataSource": dataSource,
- "schemaSource": schemaSource,
- "optionsSource": optionsSource,
- "viewSource": viewSource
- }, function(loadedData, loadedOptions, loadedSchema, loadedView) {
-
- // for cases where things could not be loaded via source loaders, fall back to what may have been passed
- // in directly as values
-
- loadedData = loadedData ? loadedData : data;
- loadedSchema = loadedSchema ? loadedSchema: schema;
- loadedOptions = loadedOptions ? loadedOptions : options;
- loadedView = loadedView ? loadedView : view;
-
- // some defaults for the case where data is null
- // if schema + options are not provided, we assume a text field
-
- if (Alpaca.isEmpty(loadedData))
- {
- if (Alpaca.isEmpty(loadedSchema) && (Alpaca.isEmpty(loadedOptions) || Alpaca.isEmpty(loadedOptions.type)))
- {
- loadedData = "";
-
- if (Alpaca.isEmpty(loadedOptions))
- {
- loadedOptions = "text";
- }
- else if (options && Alpaca.isObject(options))
- {
- loadedOptions.type = "text";
- }
- }
- }
-
- if (loadedOptions.view)
- {
- loadedView = loadedOptions.view;
- }
-
- // init alpaca
- return Alpaca.init(el, loadedData, loadedOptions, loadedSchema, loadedView, initialSettings, callback, _renderedCallback, connector, errorCallback);
-
- }, function (loadError) {
- errorCallback(loadError);
- return null;
- });
- };
-
- /**
- * @namespace Namespace for all Alpaca Field Class Implementations.
- */
- Alpaca.Fields = { };
-
- /**
- * @namespace Namespace for all Alpaca Connector Class Implementations.
- */
- Alpaca.Connectors = { };
-
- Alpaca.Extend = $.extend;
-
- Alpaca.Create = function()
- {
- var args = Array.prototype.slice.call(arguments);
- args.unshift({});
-
- return $.extend.apply(this, args);
- };
-
- // static methods and properties
- Alpaca.Extend(Alpaca,
- /** @lends Alpaca */
- {
- /**
- * Makes an array.
- *
- * @param {Any} nonArray A non-array variable.
- * @returns {Array} Array out of the non-array variable.
- */
- makeArray : function(nonArray) {
- return Array.prototype.slice.call(nonArray);
- },
-
- /**
- * Finds whether the type of a variable is function.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a function, false otherwise.
- */
- isFunction: function(obj) {
- return Object.prototype.toString.call(obj) === "[object Function]";
- },
-
- /**
- * Finds whether the type of a variable is string.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a string, false otherwise.
- */
- isString: function(obj) {
- return (typeof obj === "string");
- },
-
- /**
- * Finds whether the type of a variable is object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an object, false otherwise.
- */
- isObject: function(obj) {
- return !Alpaca.isUndefined(obj) && Object.prototype.toString.call(obj) === '[object Object]';
- },
-
- /**
- * Finds whether the type of a variable is a plain, non-prototyped object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a plain object, false otherwise.
- */
- isPlainObject: function(obj) {
- return $.isPlainObject(obj);
- },
-
- /**
- * Finds whether the type of a variable is number.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a number, false otherwise.
- */
- isNumber: function(obj) {
- return (typeof obj === "number");
- },
-
- /**
- * Finds whether the type of a variable is array.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an array, false otherwise.
- */
- isArray: function(obj) {
- return obj instanceof Array;
- },
-
- /**
- * Finds whether the type of a variable is boolean.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a boolean, false otherwise.
- */
- isBoolean: function(obj) {
- return (typeof obj === "boolean");
- },
-
- /**
- * Finds whether the type of a variable is undefined.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a undefined, false otherwise.
- */
- isUndefined: function(obj) {
- return (typeof obj == "undefined");
- },
-
- /**
- * Strips any excess whitespace characters from the given text.
- * Returns the trimmed string.
- *
- * @param str
- *
- * @return trimmed string
- */
- trim: function(text)
- {
- var trimmed = text;
-
- if (trimmed && Alpaca.isString(trimmed))
- {
- trimmed = trimmed.replace(/^\s+|\s+$/g, '');
- }
-
- return trimmed;
- },
-
- /**
- * Provides a safe conversion of an HTML textual string into a DOM object.
- *
- * @param x
- * @return {*}
- */
- safeDomParse: function(x)
- {
- if (x && Alpaca.isString(x))
- {
- x = Alpaca.trim(x);
-
- // convert to dom
- var converted = null;
- try
- {
- converted = $(x);
- }
- catch (e)
- {
- // make another attempt to account for safety in some browsers
- x = "displayReadonly
attribute set to false, the read-only field will not appear.",
- "type": "boolean",
- "default": false
- },
- "required": {
- "title": "Required",
- "description": "Indicates whether the field's value is required. If set to true, the field must take on a valid value and cannnot be left empty or unassigned.",
- "type": "boolean",
- "default": false
- },
- "default": {
- "title": "Default",
- "description": "The default value to be assigned for this property. If the data for the field is empty or not provided, this default value will be plugged in for you. Specify a default value when you want to pre-populate the field's value ahead of time.",
- "type": "any"
- },
- "type": {
- "title": "Type",
- "description": "Data type of the property.",
- "type": "string",
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Data format of the property.",
- "type": "string"
- },
- "disallow": {
- "title": "Disallowed Values",
- "description": "List of disallowed values for the property.",
- "type": "array"
- },
- "dependencies": {
- "title": "Dependencies",
- "description": "List of property dependencies.",
- "type": "array"
- }
- }
- };
- if (this.getType && !Alpaca.isValEmpty(this.getType())) {
- schemaOfSchema.properties.type['default'] = this.getType();
- schemaOfSchema.properties.type['enum'] = [this.getType()];
- }
- return schemaOfSchema;
- },
-
- /**
- * Returns Alpaca options for the schema properties that managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the schema properties that are managed by this class.
- */
- getOptionsForSchema: function() {
- return {
- "fields": {
- "title": {
- "helper": "Field short description",
- "type": "text"
- },
- "description": {
- "helper": "Field detailed description",
- "type": "textarea"
- },
- "readonly": {
- "helper": "Field will be read only if checked",
- "rightLabel": "This field is read-only",
- "type": "checkbox"
- },
- "required": {
- "helper": "Field value must be set if checked",
- "rightLabel": "This field is required",
- "type": "checkbox"
- },
- "default": {
- "helper": "Field default value",
- "type": "textarea"
- },
- "type": {
- "helper": "Field data type",
- "type": "text"
- },
- "format": {
- "type": "select",
- "dataSource": function(callback) {
- for (var key in Alpaca.defaultFormatFieldMapping)
- {
- this.selectOptions.push({
- "value": key,
- "text": key
- });
- }
-
- callback();
- }
- },
- "disallow": {
- "helper": "Disallowed values for the field",
- "itemLabel":"Value",
- "type": "array"
- },
- "dependencies": {
- "helper": "Field Dependencies",
- "multiple":true,
- "size":3,
- "type": "select",
- "dataSource": function (field, callback) {
- if (field.parent && field.parent.schemaParent && field.parent.schemaParent.parent) {
- for (var key in field.parent.schemaParent.parent.childrenByPropertyId) {
- if (key != field.parent.schemaParent.propertyId) { // jshint ignore:line
- field.selectOptions.push({
- "value": key,
- "text": key
- });
- }
- }
- }
- if (callback) {
- callback();
- }
- }
- }
- }
- };
- },
-
- /**
- * Returns JSON schema of the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} JSON schema of the Alpaca options that are managed by this class.
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = {
- "title": "Options for " + this.getTitle(),
- "description": this.getDescription() + " (Options)",
- "type": "object",
- "properties": {
- "form":{},
- "id": {
- "title": "Field Id",
- "description": "Unique field id. Auto-generated if not provided.",
- "type": "string"
- },
- "type": {
- "title": "Field Type",
- "description": "Field type.",
- "type": "string",
- "default": this.getFieldType(),
- "readonly": true
- },
- "validate": {
- "title": "Validation",
- "description": "Field validation is required if true.",
- "type": "boolean",
- "default": true
- },
- "showMessages": {
- "title": "Show Messages",
- "description": "Display validation messages if true.",
- "type": "boolean",
- "default": true
- },
- "disabled": {
- "title": "Disabled",
- "description": "Field will be disabled if true.",
- "type": "boolean",
- "default": false
- },
- "readonly": {
- "title": "Readonly",
- "description": "Field will be readonly if true.",
- "type": "boolean",
- "default": false
- },
- "hidden": {
- "title": "Hidden",
- "description": "Field will be hidden if true.",
- "type": "boolean",
- "default": false
- },
- "label": {
- "title": "Label",
- "description": "Field label.",
- "type": "string"
- },
- "helper": {
- "title": "Helper",
- "description": "Field help message.",
- "type": "string"
- },
- "fieldClass": {
- "title": "CSS class",
- "description": "Specifies one or more CSS classes that should be applied to the dom element for this field once it is rendered. Supports a single value, comma-delimited values, space-delimited values or values passed in as an array.",
- "type": "string"
- },
- "hideInitValidationError" : {
- "title": "Hide Initial Validation Errors",
- "description" : "Hide initial validation errors if true.",
- "type": "boolean",
- "default": false
- },
- "focus": {
- "title": "Focus",
- "description": "If true, the initial focus for the form will be set to the first child element (usually the first field in the form). If a field name or path is provided, then the specified child field will receive focus. For example, you might set focus to 'name' (selecting the 'name' field) or you might set it to 'client/name' which picks the 'name' field on the 'client' object.",
- "type": "checkbox",
- "default": true
- },
- "optionLabels": {
- "title": "Enumerated Value Labels",
- "description": "An array of string labels for items in the enum array",
- "type": "array"
- },
- "view": {
- "title": "Override of the view for this field",
- "description": "Allows for this field to be rendered with a different view (such as 'display' or 'create')",
- "type": "string"
- }
- }
- };
- if (this.isTopLevel()) {
-
- schemaOfOptions.properties.form = {
- "title": "Form",
- "description": "Options for rendering the FORM tag.",
- "type": "object",
- "properties": {
- "attributes": {
- "title": "Form Attributes",
- "description": "List of attributes for the FORM tag.",
- "type": "object",
- "properties": {
- "id": {
- "title": "Id",
- "description": "Unique form id. Auto-generated if not provided.",
- "type": "string"
- },
- "action": {
- "title": "Action",
- "description": "Form submission endpoint",
- "type": "string"
- },
- "method": {
- "title": "Method",
- "description": "Form submission method",
- "enum":["post","get"],
- "type": "string"
- },
- "rubyrails": {
- "title": "Ruby On Rails",
- "description": "Ruby on Rails Name Standard",
- "enum": ["true", "false"],
- "type": "string"
- },
- "name": {
- "title": "Name",
- "description": "Form name",
- "type": "string"
- },
- "focus": {
- "title": "Focus",
- "description": "Focus Setting",
- "type": "any"
- }
- }
- },
- "buttons": {
- "title": "Form Buttons",
- "description": "Configuration for form-bound buttons",
- "type": "object",
- "properties": {
- "submit": {
- "type": "object",
- "title": "Submit Button",
- "required": false
- },
- "reset": {
- "type": "object",
- "title": "Reset button",
- "required": false
- }
- }
- },
- "toggleSubmitValidState": {
- "title": "Toggle Submit Valid State",
- "description": "Toggle the validity state of the Submit button",
- "type": "boolean",
- "default": true
- }
- }
- };
-
- } else {
- delete schemaOfOptions.properties.form;
- }
-
- return schemaOfOptions;
- },
-
- /**
- * Returns Alpaca options for the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the Alpaca options that are managed by this class.
- */
- getOptionsForOptions: function() {
- var optionsForOptions = {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "type": {
- "type": "text"
- },
- "validate": {
- "rightLabel": "Enforce validation",
- "type": "checkbox"
- },
- "showMessages": {
- "rightLabel":"Show validation messages",
- "type": "checkbox"
- },
- "disabled": {
- "rightLabel":"Disable this field",
- "type": "checkbox"
- },
- "hidden": {
- "type": "checkbox",
- "rightLabel": "Hide this field"
- },
- "label": {
- "type": "text"
- },
- "helper": {
- "type": "textarea"
- },
- "fieldClass": {
- "type": "text"
- },
- "hideInitValidationError": {
- "rightLabel": "Hide initial validation errors",
- "type": "checkbox"
- },
- "focus": {
- "type": "checkbox",
- "rightLabel": "Auto-focus first child field"
- },
- "optionLabels": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "view": {
- "type": "text"
- }
- }
- };
- if (this.isTopLevel()) {
- optionsForOptions.fields.form = {
- "type": "object",
- "fields": {
- "attributes": {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "action": {
- "type": "text"
- },
- "method": {
- "type": "select"
- },
- "name": {
- "type": "text"
- }
- }
- }
- }
- };
- }
-
- return optionsForOptions;
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "disallowValue": "{0} are disallowed values.",
- "notOptional": "This field is not optional."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ControlField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ControlField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a control field.
- */
- onConstruct: function()
- {
- var _this = this;
-
- this.isControlField = true;
-
- // helper method for getting val() from the control
- // handles conversion to the correct scalar type
- this._getControlVal = function(ensureProperType) {
- var val = null;
-
- if (this.control)
- {
- val = $(this.control).val();
-
- if (ensureProperType)
- {
- val = _this.ensureProperType(val);
- }
- }
-
- return val;
- };
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var controlTemplateType = self.resolveControlTemplateType();
- if (!controlTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for control: " + self.getFieldType());
- }
-
- this.controlDescriptor = this.view.getTemplateDescriptor("control-" + controlTemplateType, self);
- },
-
- getControlEl: function()
- {
- return this.control;
- },
-
- resolveControlTemplateType: function()
- {
- var self = this;
-
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("control-" + b.getFieldType(), self);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- onSetup: function()
- {
-
- },
-
- isAutoFocusable: function()
- {
- return true;
- },
-
- /**
- * For control fields, we use the "control" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "control";
- },
-
- /**
- * Add a "control" dom element inside of the field which houses our custom control.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.control = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTROL_FIELD);
- this.control.removeClass(Alpaca.MARKER_CLASS_CONTROL_FIELD);
-
- // render
- self.prepareControlModel(function(model) {
- self.beforeRenderControl(model, function() {
- self.renderControl(model, function(controlField) {
-
- if (controlField)
- {
- self.control.replaceWith(controlField);
- self.control = controlField;
-
- self.control.addClass(Alpaca.CLASS_CONTROL);
- }
-
- // CALLBACK: "control"
- self.fireCallback("control");
-
- self.afterRenderControl(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the control.
- *
- * @param callback function(model)
- */
- prepareControlModel: function(callback)
- {
- var self = this;
-
- var model = {};
- model.id = this.getId();
- model.name = this.name;
- model.options = this.options;
- model.schema = this.schema;
- model.data = this.data;
- model.required = this.isRequired();
- model.view = this.view;
-
- callback(model);
- },
-
- /**
- * Called before the control is rendered.
- *
- * @extension-point
- *
- * @param callback
- */
- beforeRenderControl: function(model, callback)
- {
- callback();
- },
-
- /**
- * Called after the control is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- if (!self.firstUpdateObservableFire)
- {
- if ((typeof(self.data) == "undefined") || self.data == null)
- {
- // do not handle
- }
- else
- {
- self.firstUpdateObservableFire = true;
- self.updateObservable();
- }
- }
-
- callback();
- },
-
- /**
- * Renders the control into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderControl: function(model, callback)
- {
- var control = null;
-
- if (this.controlDescriptor)
- {
- control = Alpaca.tmpl(this.controlDescriptor, model);
- }
-
- callback(control);
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- /*
- // store reference to the label
- this.labelDiv = $(this.field).find(".alpaca-controlfield-label");
- var labelDiv = $('.alpaca-controlfield-label', this.outerEl);
- if (labelDiv.length) {
- this.labelDiv = labelDiv;
- }
-
- var helperDiv = $('.alpaca-controlfield-helper', this.outerEl);
- if (helperDiv.length) {
- this.helperDiv = helperDiv;
- }
- */
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#setDefault
- */
- setDefault: function() {
- var defaultData = Alpaca.isEmpty(this.schema['default']) ? "" : this.schema['default'];
- this.setValue(defaultData);
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- if (this.schema["enum"]) {
- var val = this.data;
- val = this.getValue();
- /*this.getValue();*/
- if (!this.isRequired() && Alpaca.isValEmpty(val)) {
- return true;
- }
- if ($.inArray(val, this.schema["enum"]) > -1) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateEnum();
- valInfo["invalidValueOfEnum"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidValueOfEnum"), [this.schema["enum"].join(', '), this.data]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidValueOfEnum"]["status"];
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- this.initControlEvents();
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- var control = this.control;
-
- control.click(function(e) {
- self.onClick.call(self, e);
- self.trigger("click", e);
- });
-
- // trigger control level handlers for things that happen to input element
- control.change(function(e) {
-
- // we use a timeout here because we want this to run AFTER control click handlers
- setTimeout(function() {
- self.onChange.call(self, e);
- self.triggerWithPropagation("change", e);
- }, 250);
- });
-
- control.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- control.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
-
- control.keypress(function(e) {
- self.onKeyPress.call(self, e);
- self.trigger("keypress", e);
- });
-
- control.keyup(function(e) {
- self.onKeyUp.call(self, e);
- self.trigger("keyup", e);
- });
-
- control.keydown(function(e) {
- self.onKeyDown.call(self, e);
- self.trigger("keydown", e);
- });
- },
-
- /**
- * Callback for when a key press event is received for the field control.
- *
- * @param {Object} e keypress event
- */
- onKeyPress: function(e)
- {
- var self = this;
-
- // if the field is currently invalid, then we provide early feedback to the user as to when they enter
- // if the field was valid, we don't render invalidation feedback until they blur the field
-
- // was the control valid previously?
- var wasValid = this.isValid();
- if (!wasValid)
- {
- //
- // we use a timeout because at this exact moment, the value of the control is still the old value
- // jQuery raises the keypress event ahead of the input receiving the new data which would incorporate
- // the key that was pressed
- //
- // this timeout provides the browser with enough time to plug the value into the input control
- // which the validation logic uses to determine whether the control is now in a valid state
- //
- window.setTimeout(function() {
- self.refreshValidationState();
- }, 50);
- }
-
- },
-
- /**
- * Callback for when a key down event is received for the field control.
- *
- * @param {Object} e keydown event
- */
- onKeyDown: function(e)
- {
- },
-
- /**
- * Callback for when a key up event is received for the field control.
- *
- * @param {Object} e keyup event
- */
- onKeyUp: function(e)
- {
- },
-
- /**
- * Handler for click event.
- *
- * @param {Object} e Click event.
- */
- onClick: function(e)
- {
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", true);
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", false);
- }
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumerated Values",
- "description": "List of specific values for this property",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "enum": {
- "itemLabel":"Value",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "name": {
- "title": "Field Name",
- "description": "Field Name.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "name": {
- "type": "text"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "invalidValueOfEnum": "This field should have one of the values in {0}. Current value is: {1}"
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ContainerField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ContainerField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a container field.
- */
- onConstruct: function()
- {
- this.isContainerField = true;
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return true;
- },
-
- getContainerEl: function()
- {
- return this.container;
- },
-
- /**
- * For container fields, we use the "container" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "container";
- },
-
- resolveContainerTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType(), this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- resolveContainerItemTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType() + "-item", this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerTemplateType = self.resolveContainerTemplateType();
- if (!containerTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container: " + self.getFieldType());
- }
-
- this.containerDescriptor = this.view.getTemplateDescriptor("container-" + containerTemplateType, self);
-
- var collapsible = true;
-
- if (!Alpaca.isEmpty(this.view.collapsible)) {
- collapsible = this.view.collapsible;
- }
-
- if (!Alpaca.isEmpty(this.options.collapsible)) {
- collapsible = this.options.collapsible;
- }
-
- this.options.collapsible = collapsible;
-
- var legendStyle = "button";
-
- if (!Alpaca.isEmpty(this.view.legendStyle)) {
- legendStyle = this.view.legendStyle;
- }
-
- if (!Alpaca.isEmpty(this.options.legendStyle)) {
- legendStyle = this.options.legendStyle;
- }
-
- this.options.legendStyle = legendStyle;
-
- //Lazy loading
- this.lazyLoading = false;
- if (!Alpaca.isEmpty(this.options.lazyLoading)) {
- this.lazyLoading = this.options.lazyLoading;
- if (this.lazyLoading) {
- this.options.collapsed = true;
- }
- //delete this.options.lazyLoading;
- }
- // holders of references to children
- this.children = [];
- this.childrenById = {};
- this.childrenByPropertyId = {};
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // if this container is DOM-wrapped with a form, then release the form
- if (this.form)
- {
- this.form.destroy(true); // pass in true so that we don't call back recursively
- delete this.form;
- }
-
- // destroy any child controls
- Alpaca.each(this.children, function() {
- this.destroy();
- });
-
- // call up to base method
- this.base();
- },
-
- /**
- * Add a "container" dom element inside of the field which houses our custom container.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.container = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD);
- this.container.removeClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD);
-
- // render
- self.prepareContainerModel(function(model) {
- self.beforeRenderContainer(model, function() {
- self.renderContainer(model, function(containerField) {
-
- if (containerField)
- {
- self.container.replaceWith(containerField);
- self.container = containerField;
-
- self.container.addClass(Alpaca.CLASS_CONTAINER);
- }
-
- // mark the form field with "alpaca-horizontal" or "alpaca-vertical"
- if (self.view.horizontal)
- {
- self.container.addClass("alpaca-horizontal");
- }
- else
- {
- self.container.addClass("alpaca-vertical");
- }
-
- // CALLBACK: "container"
- self.fireCallback("container");
-
- self.afterRenderContainer(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the container.
- *
- * @param callback function(model)
- */
- prepareContainerModel: function(callback)
- {
- var self = this;
-
- var model = {
- "id": this.getId(),
- "name": this.name,
- "schema": this.schema,
- "options": this.options,
- "view": this.view
- };
-
- // load items into array and store on model for future use
- self.createItems(function(items) {
-
- if (!items)
- {
- items = [];
- }
-
- // legacy support: assume containerItemEl = fieldEl
- for (var i = 0; i < items.length; i++)
- {
- if (!items[i].containerItemEl) {
- items[i].containerItemEl = items[i].getFieldEl();
- }
- }
-
- model.items = items;
-
- callback(model);
-
- });
- },
-
- /**
- * Called before the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- beforeRenderContainer: function(model, callback)
- {
- var self = this;
-
- callback();
- },
-
- /**
- * Renders the container into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderContainer: function(model, callback)
- {
- var container = null;
-
- if (this.containerDescriptor)
- {
- container = Alpaca.tmpl(this.containerDescriptor, model);
- }
-
- callback(container);
- },
-
- /**
- * Called after the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- self.beforeApplyCreatedItems(model, function() {
- self.applyCreatedItems(model, function () {
- self.afterApplyCreatedItems(model, function () {
- callback();
- });
- });
- });
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- var self = this;
-
- this.base();
-
- /*
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
- */
- },
-
- /**
- * Creates any sub-items for this container.
- *
- * @extension_point
- *
- * @param callback
- */
- createItems: function(callback)
- {
- callback();
- },
-
- beforeApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.isTopLevel() && self.view.getLayout())
- {
- layoutBindings = self.view.getLayout().bindings;
-
- // if layout and bindings not provided, assume a default strategy
- if (!layoutBindings && self.view.getLayout().templateDescriptor && model.items.length > 0)
- {
- layoutBindings = {};
-
- for (var i = 0; i < model.items.length; i++)
- {
- var name = model.items[i].name;
-
- layoutBindings[name] = "[data-alpaca-layout-binding='" + name + "']";
- }
- }
-
- }
-
- if (model.items.length > 0)
- {
- $(self.container).addClass("alpaca-container-has-items");
- $(self.container).attr("data-alpaca-container-item-count", model.items.length);
- }
- else
- {
- $(self.container).removeClass("alpaca-container-has-items");
- $(self.container).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < model.items.length; i++)
- {
- var item = model.items[i];
-
- // find the insertion point
- var insertionPoint = $(self.container).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM + "[" + Alpaca.MARKER_DATA_CONTAINER_FIELD_ITEM_KEY + "='" + item.name + "']");
- if (!layoutBindings)
- {
- var holder = $(insertionPoint).parent();
-
- $(insertionPoint).replaceWith(item.containerItemEl);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- else
- {
- // use a layout
- var bindingId = layoutBindings[item.name];
- if (bindingId)
- {
- var holder = $(bindingId, self.field);
- if (holder.length == 0)
- {
- // legacy support, fallback to ID based
- try {
- holder = $('#' + bindingId, self.field);
- } catch (e) { }
- }
- if (holder.length > 0)
- {
- $(item.containerItemEl).appendTo(holder);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- }
-
- // remove insertion point
- $(insertionPoint).remove();
- }
-
- $(item.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-first");
- }
-
- if (i + 1 === model.items.length)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(item.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(item.containerItemEl).attr("data-alpaca-container-item-name", item.name);
- $(item.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
-
- // register the child
- self.registerChild(item, i);
- }
-
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
-
- self.triggerUpdate();
- callback();
- },
-
- afterApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- /**
- * Helper method to add child field.
- *
- * @param {Alpaca.Control} child Child field to be added.
- * @param {Integer} index Index of the new child.
- */
- registerChild: function(child, index)
- {
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 0, child);
- }
- else
- {
- this.children.push(child);
- }
-
- this.childrenById[child.getId()] = child;
- if (child.propertyId)
- {
- this.childrenByPropertyId[child.propertyId] = child;
- }
-
- child.parent = this;
- },
-
- /**
- * Helper method to remove child field.
- *
- * @param index
- */
- unregisterChild: function(index)
- {
- var child = this.children[index];
- if (!child)
- {
- return;
- }
-
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 1);
- }
-
- delete this.childrenById[child.getId()];
- if (child.propertyId)
- {
- delete this.childrenByPropertyId[child.propertyId];
- }
-
- child.parent = null;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updateChildDOMElements: function()
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.view.getLayout()) {
- layoutBindings = self.view.getLayout().bindings;
- }
-
- if (!layoutBindings)
- {
- if (self.children.length > 0)
- {
- $(self.getContainerEl()).addClass("alpaca-container-has-items");
- $(self.getContainerEl()).attr("data-alpaca-container-item-count", self.children.length);
- }
- else
- {
- $(self.getContainerEl()).removeClass("alpaca-container-has-items");
- $(self.getContainerEl()).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < self.children.length; i++)
- {
- var child = self.children[i];
-
- // reset path and name
- child.path = self.path + "[" + i + "]";
- child.calculateName();
-
- $(child.containerItemEl).removeClass("alpaca-container-item-first");
- $(child.containerItemEl).removeClass("alpaca-container-item-last");
- $(child.containerItemEl).removeClass("alpaca-container-item-index");
- $(child.containerItemEl).removeClass("alpaca-container-item-key");
-
- $(child.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-first");
- }
- if (i + 1 === self.children.length)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(child.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(child.containerItemEl).attr("data-alpaca-container-item-name", child.name);
- $(child.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
- }
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentReveal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentReveal();
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentConceal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentConceal();
- }
- },
-
- /**
- * Focus an element in the container. Find the first invalid element or if no invalid elements, pick
- * the first child.
- */
- focus: function()
- {
- this.base();
-
- var index = -1;
-
- for (var i = 0; i < this.children.length; i++)
- {
- if (!this.children[i].isValid(true))
- {
- index = i;
- break;
- }
- }
- if (index === -1 && this.children.length > 0)
- {
- index = 0;
- }
-
- if (index > -1)
- {
- this.children[index].focus();
- }
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].disable();
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].enable();
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "lazyLoading": {
- "title": "Lazy Loading",
- "description": "Child fields will only be rendered when the fieldset is expanded if this option is set true.",
- "type": "boolean",
- "default": false
- },
- "collapsible": {
- "title": "Collapsible",
- "description": "Field set is collapsible if true.",
- "type": "boolean",
- "default": true
- },
- "collapsed": {
- "title": "Collapsed",
- "description": "Field set is initially collapsed if true.",
- "type": "boolean",
- "default": false
- },
- "legendStyle": {
- "title": "Legend Style",
- "description": "Field set legend style.",
- "type": "string",
- "enum":["button","link"],
- "default": "button"
- },
- "animate": {
- "title": "Animate movements and transitions",
- "description": "Up and down transitions will be animated",
- "type": "boolean",
- "default": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "lazyLoading": {
- "rightLabel": "Lazy loading child fields ?",
- "helper": "Lazy loading will be enabled if checked.",
- "type": "checkbox"
- },
- "collapsible": {
- "rightLabel": "Field set collapsible ?",
- "helper": "Field set is collapsible if checked.",
- "type": "checkbox"
- },
- "collapsed": {
- "rightLabel": "Field set initially collapsed ?",
- "description": "Field set is initially collapsed if checked.",
- "type": "checkbox"
- },
- "legendStyle": {
- "type":"select"
- },
- "animate": {
- "rightLabel": "Animate movements and transitions",
- "type": "checkbox"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Connector = Base.extend(
- /**
- * @lends Alpaca.Connector.prototype
- */
- {
- /**
- * @constructs
- * @class Connects Alpaca to remote data stores.
-
- * @param {String} id Connector ID.
- */
- constructor: function(id)
- {
- this.id = id;
-
- // helper function to determine if a resource is a uri
- this.isUri = function(resource)
- {
- return !Alpaca.isEmpty(resource) && Alpaca.isUri(resource);
- };
-
- var ONE_HOUR = 3600000;
- this.cache = new AjaxCache('URL', true, ONE_HOUR);
- },
-
- /**
- * Makes initial connections to data source.
- *
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- connect: function (onSuccess, onError)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess();
- }
- },
-
- /**
- * Loads a template (HTML or Text).
- *
- * If the source is a URI, then it is loaded.
- * If it is not a URI, then the source is simply handed back.
- *
- * @param {Object|String} source Source to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadTemplate : function (source, onSuccess, onError)
- {
- if (!Alpaca.isEmpty(source))
- {
- if (Alpaca.isUri(source))
- {
- this.loadUri(source, false, function(loadedData) {
-
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loadedData);
- }
-
- }, function (loadError) {
-
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- });
- }
- else
- {
- onSuccess(source);
- }
- }
- else
- {
- onError({
- "message":"Empty data source.",
- "reason": "TEMPLATE_LOADING_ERROR"
- });
- }
- },
-
- /**
- * Loads JSON data.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback
- * @param {Function} onError onError callback
- */
- loadData: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON view.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadView: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads schema, form, view and data in a single call.
- *
- * @param {Object} resources resources
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadAll: function (resources, onSuccess, onError)
- {
- var dataSource = resources.dataSource;
- var schemaSource = resources.schemaSource;
- var optionsSource = resources.optionsSource;
- var viewSource = resources.viewSource;
-
- // we allow "schema" to contain a URI as well (backwards-compatibility)
- if (!schemaSource)
- {
- schemaSource = resources.schema;
- }
-
- // we allow "options" to contain a URI as well (backwards-compatibility)
- if (!optionsSource)
- {
- optionsSource = resources.options;
- }
-
- // we allow "view" to contain a URI as well (backwards-compatibility)
- if (!viewSource)
- {
- viewSource = resources.view;
- }
-
- var loaded = {};
-
- var loadCounter = 0;
- var invocationCount = 0;
-
- var successCallback = function()
- {
- if (loadCounter === invocationCount)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loaded.data, loaded.options, loaded.schema, loaded.view);
- }
- }
- };
-
- var errorCallback = function (loadError)
- {
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- };
-
- // count out the total # of invokes we're going to fire off
- if (dataSource)
- {
- invocationCount++;
- }
- if (schemaSource)
- {
- invocationCount++;
- }
- if (optionsSource)
- {
- invocationCount++;
- }
- if (viewSource)
- {
- invocationCount++;
- }
- if (invocationCount === 0)
- {
- // nothing to invoke, so just hand back
- successCallback();
- return;
- }
-
- // fire off all of the invokes
- if (dataSource)
- {
- this.loadData(dataSource, function(data) {
- loaded.data = data;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (schemaSource)
- {
- this.loadSchema(schemaSource, function(schema) {
- loaded.schema = schema;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (optionsSource)
- {
- this.loadOptions(optionsSource, function(options) {
- loaded.options = options;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (viewSource)
- {
- this.loadView(viewSource, function(view) {
- loaded.view = view;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- },
-
- /**
- * Loads a JSON through Ajax call.
- *
- * @param {String} uri location of the json document
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadJson : function(uri, onSuccess, onError) {
- this.loadUri(uri, true, onSuccess, onError);
- } ,
-
- /**
- * Loads a general document through Ajax call.
- *
- * This uses jQuery to perform the Ajax call. If you need to customize connectivity to your own remote server,
- * this would be the appropriate place to do so.
- *
- * @param {String} uri uri to be loaded
- * @param {Boolean} isJson Whether the document is a JSON or not.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadUri : function(uri, isJson, onSuccess, onError) {
-
- var self = this;
-
- var ajaxConfigs = {
- "url": uri,
- "type": "get",
- "success": function(jsonDocument) {
-
- self.cache.put(uri, jsonDocument);
-
- if (onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(jsonDocument);
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
- if (onError && Alpaca.isFunction(onError)) {
- onError({
- "message":"Unable to load data from uri : " + uri,
- "stage": "DATA_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- }
- };
-
- if (isJson) {
- ajaxConfigs.dataType = "json";
- } else {
- ajaxConfigs.dataType = "text";
- }
-
- var cachedDocument = self.cache.get(uri);
-
- if (cachedDocument !== false && onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(cachedDocument);
- } else {
- $.ajax(ajaxConfigs);
- }
- },
-
- /**
- * Loads referenced JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads referenced JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- _handleLoadJsonResource: function (resource, successCallback, errorCallback)
- {
- if (this.isUri(resource))
- {
- this.loadJson(resource, function(loadedResource) {
- successCallback(loadedResource);
- }, errorCallback);
- }
- else
- {
- successCallback(resource);
- }
- }
-
- });
-
- Alpaca.registerConnectorClass("default", Alpaca.Connector);
-
-
-
-
-
-
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // AJAX CACHE
- //
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
- /*!
- * ajax-cache JavaScript Library v0.2.1
- * http://code.google.com/p/ajax-cache/
- *
- * Includes few JSON methods (open source)
- * http://www.json.org/js.html
- *
- * Date: 2010-08-03
- */
- var AjaxCache = function AjaxCache(type, on, lifetime) {
- if (on) {
- this.on = true;
- } else {
- this.on = false;
- }
-
- // set default cache lifetime
- if (lifetime != null) {
- this.defaultLifetime = lifetime;
- }
-
- // set type
- this.type = type;
-
- // set cache functions according to type
- switch (this.type) {
- case 'URL':
- this.put = this.put_url;
- break;
- case 'GET':
- this.put = this.put_GET;
- break;
- }
-
- };
-
- AjaxCache.prototype.on = false;
- AjaxCache.prototype.type = undefined;
- AjaxCache.prototype.defaultLifetime = 1800000; // 1800000=30min, 300000=5min, 30000=30sec
- AjaxCache.prototype.items = {};
-
- /**
- * Caches the request and its response. Type: url
- *
- * @param url - url of ajax response
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_url = function(url, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Caches the request and its response. Type: GET
- *
- * @param url - url of ajax response
- * @param data - data params (query)
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_GET = function(url, data, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url, [ data ]);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].data = data;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Get cached ajax response
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return ajax response or false if such does not exist or is expired
- */
- AjaxCache.prototype.get = function(url, params) {
- var key = this.make_key(url, params);
-
- // if cache does not exist
- if (this.items[key] == null) {
- return false;
- }
-
- // if cache expired
- if (this.items[key].expire < (new Date().getTime())) {
- return false;
- }
-
- // everything is passed - lets return the response
- return this.items[key].response;
- };
-
- /**
- * Make unique key for each request depending on url and additional parameters
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return unique key
- */
- AjaxCache.prototype.make_key = function(url, params) {
- var key = url;
- switch (this.type) {
- case 'URL':
- break;
- case 'GET':
- key += this.stringify(params[0]);
- break;
- }
-
- return key;
- };
-
- /**
- * Flush cache
- *
- * @return true on success
- */
- AjaxCache.prototype.flush = function() {
- // flush all cache
- cache.items = {};
- return true;
- };
-
- /*
- * Methods to stringify JavaScript/JSON objects.
- *
- * Taken from: http://www.json.org/js.html to be more exact, this file:
- * http://www.json.org/json2.js copied on 2010-07-19
- *
- * Taken methods: stringify, quote and str
- *
- * Methods are slightly modified to best fit ajax-cache functionality
- *
- */
- AjaxCache.prototype.stringify = function(value, replacer, space) {
-
- // The stringify method takes a value and an optional replacer, and an
- // optional
- // space parameter, and returns a JSON text. The replacer can be a function
- // that can replace values, or an array of strings that will select the
- // keys.
- // A default replacer method can be provided. Use of the space parameter can
- // produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
- // If the space parameter is a number, make an indent string containing that
- // many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
- // If the space parameter is a string, it will be used as the indent
- // string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
- // If there is a replacer, it must be a function or an array.
- // Otherwise, throw an error.
-
- rep = replacer;
- if (replacer &&
- typeof replacer !== 'function' &&
- (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
- // Make a fake root object containing our value under the key of ''.
- // Return the result of stringifying the value.
-
- return this.str('', {
- '' : value
- });
- };
-
- AjaxCache.prototype.quote = function(string) {
-
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe escape
- // sequences.
-
- var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable,
- function(a) {
- var c = meta[a];
- return typeof c === 'string' ? c : '\\u' + ('0000' + a
- .charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- };
-
- AjaxCache.prototype.str = function(key, holder) {
-
- // Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length, mind = gap, partial, value = holder[key];
-
- // If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value &&
- typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
- // If we were called with a replacer function, then call the replacer to
- // obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
- // What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return this.quote(value);
-
- case 'number':
-
- // JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
- // If the value is a boolean or null, convert it to a string. Note:
- // typeof null does not produce 'null'. The case is included here in
- // the remote chance that this gets fixed someday.
-
- return String(value);
-
- // If the type is 'object', we might be dealing with an object or an
- // array or
- // null.
-
- case 'object':
-
- // Due to a specification blunder in ECMAScript, typeof null is
- // 'object',
- // so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
- // Make an array to hold the partial results of stringifying this object
- // value.
-
- gap += indent;
- partial = [];
-
- // Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
- // The value is an array. Stringify every element. Use null as a
- // placeholder
- // for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = this.str(i, value) || 'null';
- }
-
- // Join all of the elements together, separated with commas, and
- // wrap them in
- // brackets.
-
- v = partial.length === 0 ? '[]' : gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
- // If the replacer is an array, use it to select the members to be
- // stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
- // Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
- // Join all of the member texts together, separated with commas,
- // and wrap them in braces.
-
- v = partial.length === 0 ?
- '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- };
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Form = Base.extend(
- /**
- * @lends Alpaca.Form.prototype
- */
- {
- /**
- * @constructs
- *
- * @class This class is for managing HTML form control.
- *
- * @param {Object} container Field container.
- * @param {Object} options Field options.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(domEl, options, viewId, connector, errorCallback) {
-
- // container
- this.domEl = domEl;
-
- // parent
- this.parent = null;
-
- this.connector = connector;
- this.errorCallback = errorCallback;
-
- // options
- this.options = options;
-
- if (this.options.attributes)
- {
- this.attributes = this.options.attributes;
- }
- else
- {
- this.attributes = {};
- }
-
- if (this.options.buttons)
- {
- if (this.options.buttons.submit)
- {
- if (!this.options.buttons.submit.type)
- {
- this.options.buttons.submit.type = 'submit';
- }
-
- if (!this.options.buttons.submit.name)
- {
- this.options.buttons.submit.name = 'submit';
- }
-
- if (!this.options.buttons.submit.value)
- {
- this.options.buttons.submit.value = 'Submit';
- }
- }
-
- if (this.options.buttons.reset)
- {
- if (!this.options.buttons.reset.type)
- {
- this.options.buttons.reset.type = 'reset';
- }
- if (!this.options.buttons.reset.name)
- {
- this.options.buttons.reset.name = 'reset';
- }
- if (!this.options.buttons.reset.value)
- {
- this.options.buttons.reset.value = 'Reset';
- }
- }
-
- // some general correction
- for (var k in this.options.buttons)
- {
- if (this.options.buttons[k].label)
- {
- this.options.buttons[k].value = this.options.buttons[k].label;
- }
- if (this.options.buttons[k].title)
- {
- this.options.buttons[k].value = this.options.buttons[k].title;
- }
- if (!this.options.buttons[k].type)
- {
- this.options.buttons[k].type = "button";
- }
- }
- }
-
- if (this.attributes.id)
- {
- this.id = this.attributes.id;
- }
- else
- {
- this.id = Alpaca.generateId();
- this.attributes.id = this.id;
- }
-
- // if we have a submit button specified, and toggleSubmitValidState isn't defined, set to true by default
- // don't allow the form to submit unless valid
- if (this.options.buttons && this.options.buttons.submit && Alpaca.isUndefined(this.options.toggleSubmitValidState))
- {
- this.options.toggleSubmitValidState = true;
- }
-
- this.viewType = options.viewType;
-
- // set a runtime view
- this.view = new Alpaca.RuntimeView(viewId, this);
- },
-
- /**
- * Renders this form into the container.
- *
- * @param {Function} callback
- */
- render: function(callback)
- {
- var self = this;
-
- // remove the previous form element if it exists
- if (this.form)
- {
- this.form.remove();
- }
-
- // load the appropriate template and render it
- this.processRender(this.domEl, function() {
-
- // bind our field dom element into the container
- self.form.appendTo(self.container);
-
- // add default class
- self.form.addClass("alpaca-form");
-
- // CALLBACK: "form"
- self.fireCallback("form");
-
- // execute callback
- callback(self);
- });
- },
-
- /**
- * Determines whether the top control is entirely valid.
- *
- * @return {*}
- */
- isFormValid: function()
- {
- // re-compute validation for the full control set
- this.topControl.validate(true);
-
- var valid = this.topControl.isValid(true);
- //this.refreshValidationState(true);
-
- return valid;
- },
-
- isValid: function()
- {
- return this.isFormValid();
- },
-
- validate: function(children)
- {
- return this.topControl.validate(children);
- },
-
- enableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", false);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- disableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", true);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- adjustSubmitButtonState: function()
- {
- this.disableSubmitButton();
-
- if (this.isFormValid())
- {
- this.enableSubmitButton();
- }
- },
-
- /**
- * Responsible for fetching any templates needed so as to render the
- * current mode for this field.
- *
- * Once completed, the onSuccess method is called.
- *
- * @param {Object} parentEl Field container.
- * @param {Function} callback
- */
- processRender: function(parentEl, callback)
- {
- var self = this;
-
- // lookup the template we should use to render
- this.formDescriptor = this.view.getTemplateDescriptor("form");
- if (!this.formDescriptor)
- {
- return Alpaca.throwErrorWithCallback("Could not find template descriptor: form");
- }
-
- var renderedDomElement = Alpaca.tmpl(this.formDescriptor, {
- id: this.getId(),
- options: this.options,
- view: this.view
- });
- renderedDomElement.appendTo(parentEl);
-
- this.form = renderedDomElement;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.formFieldsContainer = $(this.form).find("." + Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
- this.formFieldsContainer.removeClass(Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
-
- if (Alpaca.isEmpty(this.form.attr("id")))
- {
- this.form.attr("id", this.getId() + "-form-outer");
- }
- if (Alpaca.isEmpty(this.form.attr("data-alpaca-form-id")))
- {
- this.form.attr("data-alpaca-form-id", this.getId());
- }
-
- // the form field
- parentEl.find("form").attr(this.attributes);
-
- // populate the buttons as well
- this.buttons = {};
- $(parentEl).find(".alpaca-form-button").each(function() {
-
- $(this).click(function(e) {
- $(this).attr("button-pushed", true);
- });
-
- // custom click handler?
- var key = $(this).attr("data-key");
- if (key)
- {
- var buttonConfig = self.options.buttons[key];
- if (buttonConfig)
- {
- if (buttonConfig.click)
- {
- $(this).click(function(form, handler) {
- return function(e) {
- e.preventDefault();
- handler.call(form, e);
- }
- }(self, buttonConfig.click));
- }
- }
- }
- });
-
- callback();
- },
-
- /**
- * Returns the id of the form.
- *
- * @returns {String} Form id
- */
- getId: function()
- {
- return this.id;
- },
-
- /**
- * Returns form type.
- *
- * @returns {String} Form type.
- */
- getType: function()
- {
- return this.type;
- },
-
- /**
- * Returns this form's parent.
- *
- * @returns {Object} Form parent.
- */
- getParent: function()
- {
- return this.parent;
- },
-
- /**
- * Returns the value of the JSON rendered by this form.
- *
- * @returns {Any} Value of the JSON rendered by this form.
- */
- getValue: function()
- {
- return this.topControl.getValue();
- },
-
- /**
- * Sets the value of the JSON to be rendered by this form.
- *
- * @param {Any} value Value to be set.
- */
- setValue: function(value)
- {
- this.topControl.setValue(value);
- },
-
- /**
- * Initializes events handling (Form Submission) for this form.
- */
- initEvents: function()
- {
- var _this = this;
-
- var formTag = $(this.domEl).find("form");
-
- var v = this.getValue();
- $(formTag).submit(v, function(e) {
- return _this.onSubmit(e, _this);
- });
-
- // listen for fieldupdates and determine whether the form is valid.
- // if so, enable the submit button...
- // otherwise, disable it
- if (this.options.toggleSubmitValidState)
- {
- $(_this.topControl.getFieldEl()).bind("fieldupdate", function() {
- _this.adjustSubmitButtonState();
- });
-
- this.adjustSubmitButtonState();
- }
- },
-
- getButtonEl: function(buttonId)
- {
- return $(this.domEl).find(".alpaca-form-button-" + buttonId);
- },
-
- /**
- * Handles form submit events.
- *
- * @param {Object} e Submit event.
- * @param {Object} form the form
- */
- onSubmit: function(e, form)
- {
- if (this.submitHandler)
- {
- e.stopPropagation();
-
- var v = this.submitHandler(e, form);
- if (Alpaca.isUndefined(v)) {
- v = false;
- }
-
- return v;
- }
- },
-
- /**
- * Registers a custom submit handler.
- *
- * @param {Object} func Submit handler to be registered.
- */
- registerSubmitHandler: function (func)
- {
- if (Alpaca.isFunction(func))
- {
- this.submitHandler = func;
- }
- },
-
- /**
- * Displays validation information of all fields of this form.
- *
- * @param {Boolean} children whether to render validation state for child fields
- *
- * @returns {Object} Form validation state.
- */
- refreshValidationState: function(children, callback)
- {
- this.topControl.refreshValidationState(children, callback);
- },
-
- /**
- * Disables this form.
- */
- disable: function()
- {
- this.topControl.disable();
- },
-
- /**
- * Enables this form.
- */
- enable: function()
- {
- this.topControl.enable();
- },
-
- /**
- * Focuses on this form.
- */
- focus: function()
- {
- this.topControl.focus();
- },
-
- /**
- * Purge any event listeners and remove the form from the DOM.
- *
- * @param [Boolean] skipParent when true, the form cleans up without traversing through parent child controls
- */
- destroy: function(skipParent)
- {
- this.getFormEl().remove();
-
- // we allow form.destroy() which tells parent control to destroy
- // if skipParent == true, then we do not call up (invoked from container)
- if (!skipParent && this.parent)
- {
- this.parent.destroy();
- }
- },
-
- /**
- * Shows the form.
- */
- show: function()
- {
- this.getFormEl().css({
- "display": ""
- });
- },
-
- /**
- * Hides the form.
- */
- hide: function()
- {
- this.getFormEl().css({
- "display": "none"
- });
- },
-
- /**
- * Clears the form and resets values of its fields.
- *
- * @param stopUpdateTrigger If false, triggers the update event of this event.
- */
- clear: function(stopUpdateTrigger)
- {
- this.topControl.clear(stopUpdateTrigger);
- },
-
- /**
- * Checks if form is empty.
- *
- * @returns {Boolean} True if the form is empty, false otherwise.
- */
- isEmpty: function()
- {
- return this.topControl.isEmpty();
- },
-
- /**
- * Fires a view callback for the current form.
- *
- * @param id
- * @param arg1
- * @param arg2
- * @param arg3
- * @param arg4
- * @param arg5
- */
- fireCallback: function(id, arg1, arg2, arg3, arg4, arg5)
- {
- this.view.fireCallback(this, id, arg1, arg2, arg3, arg4, arg5);
- },
-
- /**
- * Retrieves the form element.
- *
- * @returns {Object} The rendered DOM element.
- */
- getFormEl: function() {
- return this.form;
- },
-
- /**
- * Performs a regular old submit.
- */
- submit: function()
- {
- this.form.submit();
- },
-
- /**
- * Fires the submit in the background and hands back the jQuery promise.
- *
- * @returns {*}
- */
- ajaxSubmit: function()
- {
- var self = this;
-
- return $.ajax({
- data: this.getValue(),
- url: self.options.attributes.action,
- type: self.options.attributes.method,
- dataType: "json"
- });
- }
-
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.TextField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "text";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
-
- /*
- if (!this.options.size) {
- this.options.size = 40;
- }
- */
-
- // assume html5 input type = "text"
- if (!this.inputType)
- {
- this.inputType = "text";
- }
-
- if (this.options.inputType)
- {
- this.inputType = this.options.inputType;
- }
-
- // DOM data-* attributes support
- if (!this.options.data)
- {
- this.options.data = {};
- }
-
- // DOM * attributes support
- if (!this.options.attributes)
- {
- this.options.attributes = {};
- }
-
- if (typeof(this.options.allowOptionalEmpty) == "undefined")
- {
- this.options.allowOptionalEmpty = true;
- }
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- this.base();
-
- // clean up typeahead
- if ( this.control && this.control.typeahead && this.options.typeahead)
- {
- $(this.control).typeahead('destroy');
- }
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- if (self.control)
- {
- // mask
- self.applyMask();
-
- // typeahead
- self.applyTypeAhead();
-
- // update max length indicator
- self.updateMaxLengthIndicator();
- }
-
- callback();
- });
- },
-
- applyMask: function()
- {
- var self = this;
-
- // mask it
- if (self.control.mask && self.options.maskString)
- {
- self.control.mask(self.options.maskString);
- }
- },
-
- applyTypeAhead: function()
- {
- var self = this;
-
- if (self.control.typeahead && self.options.typeahead && !Alpaca.isEmpty(self.options.typeahead))
- {
- var tConfig = self.options.typeahead.config;
- if (!tConfig) {
- tConfig = {};
- }
-
- var tDatasets = self.options.typeahead.datasets;
- if (!tDatasets) {
- tDatasets = {};
- }
-
- if (!tDatasets.name) {
- tDatasets.name = self.getId();
- }
-
- var tEvents = self.options.typeahead.events;
- if (!tEvents) {
- tEvents = {};
- }
-
- // support for each datasets (local, remote, prefetch)
- if (tDatasets.type === "local" || tDatasets.type === "remote" || tDatasets.type === "prefetch")
- {
- var bloodHoundConfig = {
- datumTokenizer: function(d) {
- return Bloodhound.tokenizers.whitespace(d.value);
- },
- queryTokenizer: Bloodhound.tokenizers.whitespace
- };
-
- if (tDatasets.type === "local" )
- {
- var local = [];
-
- if (typeof(tDatasets.source) === "function")
- {
- bloodHoundConfig.local = tDatasets.source;
- }
- else
- {
- // array
- for (var i = 0; i < tDatasets.source.length; i++)
- {
- var localElement = tDatasets.source[i];
- if (typeof(localElement) === "string")
- {
- localElement = {
- "value": localElement
- };
- }
-
- local.push(localElement);
- }
-
- bloodHoundConfig.local = local;
- }
-
- if (tDatasets.local)
- {
- bloodHoundConfig.local = tDatasets.local;
- }
- }
-
- if (tDatasets.type === "prefetch")
- {
- bloodHoundConfig.prefetch = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.prefetch.filter = tDatasets.filter;
- }
- }
-
- if (tDatasets.type === "remote")
- {
- bloodHoundConfig.remote = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.remote.filter = tDatasets.filter;
- }
-
- if (tDatasets.replace)
- {
- bloodHoundConfig.remote.replace = tDatasets.replace;
- }
- }
-
- var engine = new Bloodhound(bloodHoundConfig);
- engine.initialize();
- tDatasets.source = engine.ttAdapter();
- }
-
- // compile templates
- if (tDatasets.templates)
- {
- for (var k in tDatasets.templates)
- {
- var template = tDatasets.templates[k];
- if (typeof(template) === "string")
- {
- tDatasets.templates[k] = Handlebars.compile(template);
- }
- }
- }
-
- // process typeahead
- $(self.control).typeahead(tConfig, tDatasets);
-
- // listen for "autocompleted" event and set the value of the field
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // listen for "selected" event and set the value of the field
- $(self.control).on("typeahead:selected", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // custom events
- if (tEvents)
- {
- if (tEvents.autocompleted) {
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- tEvents.autocompleted(event, datum);
- });
- }
- if (tEvents.selected) {
- $(self.control).on("typeahead:selected", function(event, datum) {
- tEvents.selected(event, datum);
- });
- }
- }
-
- // when the input value changes, change the query in typeahead
- // this is to keep the typeahead control sync'd with the actual dom value
- // only do this if the query doesn't already match
- var fi = $(self.control);
- $(self.control).change(function() {
-
- var value = $(this).val();
-
- var newValue = $(fi).typeahead('val');
- if (newValue !== value)
- {
- $(fi).typeahead('val', newValue);
- }
-
- });
-
- // some UI cleanup (we don't want typeahead to restyle)
- $(self.field).find("span.twitter-typeahead").first().css("display", "block"); // SPAN to behave more like DIV, next line
- $(self.field).find("span.twitter-typeahead input.tt-input").first().css("background-color", "");
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.inputType = self.inputType;
-
- callback(model);
- });
- },
-
- updateMaxLengthIndicator: function()
- {
- var self = this;
-
- var errState = false;
-
- var message = "";
- if (!Alpaca.isEmpty(self.schema.maxLength) && self.options.showMaxLengthIndicator)
- {
- var val = self.getValue() || "";
-
- var diff = self.schema.maxLength - val.length;
- if (diff >= 0)
- {
- message = "You have " + diff + " characters remaining";
- }
- else
- {
- message = "Your message is too long by " + (diff*-1) + " characters";
- errState = true;
- }
-
- var indicator = $(self.field).find(".alpaca-field-text-max-length-indicator");
- if (indicator.length === 0)
- {
- indicator = $("");
- $(self.control).after(indicator);
- }
-
- $(indicator).html(message);
- $(indicator).removeClass("err");
- if (errState)
- {
- $(indicator).addClass("err");
- }
- }
-
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!this.isDisplayOnly() && this.control && this.control.length > 0)
- {
- value = this._getControlVal(true);
-
- if (self.control.mask && self.options.maskString)
- {
- // get unmasked value
- var fn = $(this.control).data($.mask.dataName);
- if (fn)
- {
- value = fn();
- value = self.ensureProperType(value);
- }
- }
- }
- else
- {
- value = this.base();
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (this.control && this.control.length > 0)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
- }
-
- // be sure to call into base method
- this.base(value);
-
- // if applicable, update the max length indicator
- this.updateMaxLengthIndicator();
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validatePattern();
- valInfo["invalidPattern"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidPattern"), [this.schema.pattern]),
- "status": status
- };
-
- status = this._validateMaxLength();
- valInfo["stringTooLong"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooLong"), [this.schema.maxLength]),
- "status": status
- };
-
- status = this._validateMinLength();
- valInfo["stringTooShort"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooShort"), [this.schema.minLength]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidPattern"]["status"] && valInfo["stringTooLong"]["status"] && valInfo["stringTooShort"]["status"];
- },
-
- /**
- * Validates against the schema pattern property.
- *
- * @returns {Boolean} True if it matches the pattern, false otherwise.
- */
- _validatePattern: function()
- {
- if (this.schema.pattern)
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (!val.match(this.schema.pattern))
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates against the schema minLength property.
- *
- * @returns {Boolean} True if its size is greater than minLength, false otherwise.
- */
- _validateMinLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.minLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length < this.schema.minLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates against the schema maxLength property.
- *
- * @returns {Boolean} True if its size is less than maxLength , false otherwise.
- */
- _validateMaxLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.maxLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length > this.schema.maxLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- if (this.control && this.control.length > 0)
- {
- // focuses the control and also positions the input at the end
-
- var el = $(this.control).get(0);
-
- try {
- var elemLen = el.value ? el.value.length : 0;
- el.selectionStart = elemLen;
- el.selectionEnd = elemLen;
- }
- catch (e) {
- // field type doesn't support selection start and end
- }
-
- el.focus();
- }
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyDown: function(e)
- {
- var self = this;
-
- if (e.keyCode === 8) // backspace
- {
- if (!Alpaca.isEmpty(self.schema.minLength) && (self.options.constrainLengths || self.options.constrainMinLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length <= self.schema.minLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- else
- {
- if (!Alpaca.isEmpty(self.schema.maxLength) && (self.options.constrainLengths || self.options.constrainMaxLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length >= self.schema.maxLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- },
-
- onKeyUp: function(e)
- {
- var self = this;
-
- // if applicable, update the max length indicator
- self.updateMaxLengthIndicator();
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Single-Line Text";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Text field for single-line text.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minLength": {
- "title": "Minimal Length",
- "description": "Minimal length of the property value.",
- "type": "number"
- },
- "maxLength": {
- "title": "Maximum Length",
- "description": "Maximum length of the property value.",
- "type": "number"
- },
- "pattern": {
- "title": "Pattern",
- "description": "Regular expression for the property value.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "default": {
- "helper": "Field default value",
- "type": "text"
- },
- "minLength": {
- "type": "integer"
- },
- "maxLength": {
- "type": "integer"
- },
- "pattern": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "size": {
- "title": "Field Size",
- "description": "Field size.",
- "type": "number",
- "default":40
- },
- "maskString": {
- "title": "Mask Expression",
- "description": "Expression for the field mask. Field masking will be enabled if not empty.",
- "type": "string"
- },
- "placeholder": {
- "title": "Field Placeholder",
- "description": "Field placeholder.",
- "type": "string"
- },
- "typeahead": {
- "title": "Type Ahead",
- "description": "Provides configuration for the $.typeahead plugin if it is available. For full configuration options, see: https://github.com/twitter/typeahead.js"
- },
- "allowOptionalEmpty": {
- "title": "Allow Optional Empty",
- "description": "Allows this non-required field to validate when the value is empty"
- },
- "inputType": {
- "title": "HTML5 Input Type",
- "description": "Allows for the override of the underlying HTML5 input type. If not specified, an assumed value is provided based on the kind of input control (i.e. 'text', 'date', 'email' and so forth)",
- "type": "string"
- },
- "data": {
- "title": "Data attributes for the underlying DOM input control",
- "description": "Allows you to specify a key/value map of data attributes that will be added as DOM attribuets for the underlying input control. The data attributes will be added as data-{name}='{value}'.",
- "type": "object"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "size": {
- "type": "integer"
- },
- "maskString": {
- "helper": "a - an alpha character;9 - a numeric character;* - an alphanumeric character",
- "type": "text"
- },
- "typeahead": {
- "type": "object"
- },
- "allowOptionalEmpty": {
- "type": "checkbox"
- },
- "inputType": {
- "type": "text"
- },
- "data": {
- "type": "object"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "invalidPattern": "This field should have pattern {0}",
- "stringTooShort": "This field should contain at least {0} numbers or characters",
- "stringTooLong": "This field should contain at most {0} numbers or characters"
- });
- Alpaca.registerFieldClass("text", Alpaca.Fields.TextField);
- Alpaca.registerDefaultSchemaFieldMapping("string", "text");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextAreaField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.TextAreaField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function()
- {
- return "textarea";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.options.rows) {
- this.options.rows = 5;
- }
-
- if (!this.options.cols) {
- this.options.cols = 40;
- }
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": status
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"];
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.data;
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Multi-Line Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Textarea field for multiple line text.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rows": {
- "title": "Rows",
- "description": "Number of rows",
- "type": "number",
- "default": 5
- },
- "cols": {
- "title": "Columns",
- "description": "Number of columns",
- "type": "number",
- "default": 40
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rows": {
- "type": "integer"
- },
- "cols": {
- "type": "integer"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded."
- });
-
- Alpaca.registerFieldClass("textarea", Alpaca.Fields.TextAreaField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CheckBoxField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.CheckBoxField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "checkbox";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function() {
-
- var _this = this;
-
- _this.base();
-
- if (!this.options.rightLabel) {
- this.options.rightLabel = "";
- }
-
- if (typeof(_this.options.multiple) == "undefined")
- {
- if (_this.schema.type === "array")
- {
- _this.options.multiple = true;
- }
- else if (typeof(_this.schema["enum"]) != "undefined")
- {
- _this.options.multiple = true;
- }
- }
-
- _this.checkboxOptions = [];
- if (_this.options.multiple)
- {
- $.each(_this.getEnum(), function(index, value) {
-
- var text = value;
-
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.checkboxOptions.push({
- "value": value,
- "text": text
- });
- });
- }
- },
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- var array = [];
-
- if (this.schema && this.schema["enum"])
- {
- array = this.schema["enum"];
- }
-
- return array;
- },
-
- /**
- * Handler for the event that the checkbox is clicked.
- *
- * @param e Event.
- */
- onClick: function(e)
- {
- this.refreshValidationState();
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
- model.checkboxOptions = self.checkboxOptions;
-
- callback(model);
- });
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the checked state of the control to update
- if (self.data && typeof(self.data) !== "undefined")
- {
- self.setValue(self.data);
- }
-
- // whenever the state of one of our input:checkbox controls is changed (either via a click or programmatically),
- // we signal to the top-level field to fire up a change
- //
- // this allows the dependency system to recalculate and such
- //
- $(self.getFieldEl()).find("input:checkbox").change(function(evt) {
- self.triggerWithPropagation("change");
- });
-
- // for multiple mode, mark values
- if (self.options.multiple)
- {
- // none checked
- $(self.getFieldEl()).find("input:checkbox").prop("checked", false);
-
- if (self.data)
- {
- var dataArray = self.data;
- if (typeof(self.data) === "string")
- {
- dataArray = self.data.split(",");
- for (var a = 0; a < dataArray.length; a++)
- {
- dataArray[a] = $.trim(dataArray[a]);
- }
- }
-
- for (var k in dataArray)
- {
- $(self.getFieldEl()).find("input:checkbox[data-checkbox-value=\"" + dataArray[k] + "\"]").prop("checked", true);
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!self.options.multiple)
- {
- // single scalar value
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- value = Alpaca.checked($(input[0]));
- }
- else
- {
- value = false;
- }
- }
- else
- {
- // multiple values
- var values = [];
- for (var i = 0; i < self.checkboxOptions.length; i++)
- {
- var inputField = $(self.getFieldEl()).find("input[data-checkbox-index='" + i + "']");
- if (Alpaca.checked(inputField))
- {
- var v = $(inputField).attr("data-checkbox-value");
- values.push(v);
- }
- }
-
- // determine how we're going to hand this value back
-
- // if type == "array", we just hand back the array
- // if type == "string", we build a comma-delimited list
- if (self.schema.type === "array")
- {
- value = values;
- }
- else if (self.schema.type === "string")
- {
- value = values.join(",");
- }
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- // value can be a boolean, string ("true"), string ("a,b,c") or an array of values
-
- var applyScalarValue = function(value)
- {
- if (Alpaca.isString(value)) {
- value = (value === "true");
- }
-
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- };
-
- var applyMultiValue = function(values)
- {
- // allow for comma-delimited strings
- if (typeof(values) === "string")
- {
- values = values.split(",");
- }
-
- // trim things to remove any excess white space
- for (var i = 0; i < values.length; i++)
- {
- values[i] = Alpaca.trim(values[i]);
- }
-
- // walk through values and assign into appropriate inputs
- for (var j = 0; j < values.length; j++)
- {
- var input = $(self.getFieldEl()).find("input[data-checkbox-value=\"" + values[j] + "\"]");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- }
- };
-
- var applied = false;
-
- if (!self.options.multiple)
- {
- // single value mode
-
- // boolean
- if (typeof(value) === "boolean")
- {
- applyScalarValue(value);
- applied = true;
- }
- else if (typeof(value) === "string")
- {
- applyScalarValue(value);
- applied = true;
- }
- }
- else
- {
- // multiple value mode
-
- if (typeof(value) === "string")
- {
- applyMultiValue(value);
- applied = true;
- }
- else if (Alpaca.isArray(value))
- {
- applyMultiValue(value);
- applied = true;
- }
- }
-
- if (!applied && value)
- {
- Alpaca.logError("CheckboxField cannot set value for schema.type=" + self.schema.type + " and value=" + value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * Validate against enum property in the case that the checkbox field is in multiple mode.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var self = this;
-
- if (!self.options.multiple)
- {
- return true;
- }
-
- var val = self.getValue();
- if (!self.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- // if val is a string, convert to array
- if (typeof(val) === "string")
- {
- val = val.split(",");
- }
-
- return Alpaca.anyEquality(val, self.schema["enum"]);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = true;
- });
-
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = false;
- });
-
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "boolean";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Checkbox Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Checkbox Field for boolean (true/false), string ('true', 'false' or comma-delimited string of values) or data array.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rightLabel": {
- "title": "Option Label",
- "description": "Optional right-hand side label for single checkbox field.",
- "type": "string"
- },
- "multiple": {
- "title": "Multiple",
- "description": "Whether to render multiple checkboxes for multi-valued type (such as an array or a comma-delimited string)",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rightLabel": {
- "type": "text"
- },
- "multiple": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("checkbox", Alpaca.Fields.CheckBoxField);
- Alpaca.registerDefaultSchemaFieldMapping("boolean", "checkbox");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.FileField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.FileField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "file";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- this.data = value;
-
- this.data = value;
-
- this.updateObservable();
-
- this.triggerUpdate();
- },
-
- getValue: function()
- {
- return this.data;
- },
-
- onChange: function(e)
- {
- this.base(e);
-
- if (this.options.selectionHandler)
- {
- this.processSelectionHandler(e.target.files);
- }
- },
-
- processSelectionHandler: function(files)
- {
- if (files && files.length > 0)
- {
- // if the browser supports HTML5 FileReader, we can pull in the stream for preview
- if (typeof(FileReader) !== "undefined")
- {
- // clear out previous loaded data
- var loadedData = [];
- var loadCount = 0;
-
- var fileReader = new FileReader();
- fileReader.onload = (function() {
- var field = this;
- return function(event)
- {
- var dataUri = event.target.result;
-
- loadedData.push(dataUri);
- loadCount++;
-
- if (loadCount === files.length)
- {
- field.options.selectionHandler.call(field, files, loadedData);
- }
- };
- }).call(this);
-
- for (var i = 0; i < files.length; i++)
- {
- fileReader.readAsDataURL(files[i]);
- }
- }
- }
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "File Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for uploading files.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "selectionHandler": {
- "title": "Selection Handler",
- "description": "Function that should be called when files are selected. Requires HTML5.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "selectionHandler": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("file", Alpaca.Fields.FileField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ListField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ListField.prototype
- */
- {
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var _this = this;
-
- _this.base();
-
- _this.selectOptions = [];
-
- if (_this.getEnum())
- {
- $.each(_this.getEnum(), function(index, value)
- {
- var text = value;
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.selectOptions.push({
- "value": value,
- "text": text
- });
- });
- }
-
- /**
- * Auto assign data if we have data and the field is required and removeDefaultNone is either unspecified or true
- */
- if (_this.isRequired() && !_this.data)
- {
- //if ((typeof(_this.options.removeDefaultNone) == "undefined") || _this.options.removeDefaultNone === true)
- if ((_this.options.removeDefaultNone === true))
- {
- if (_this.schema.enum && _this.schema.enum.length > 0)
- {
- _this.data = _this.schema.enum[0];
- }
- }
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.noneLabel = "None";
- if (typeof(self.options.noneLabel) != "undefined")
- {
- model.noneLabel = self.options.noneLabel;
- }
-
- model.hideNone = self.isRequired();
- if (typeof(self.options.removeDefaultNone) != "undefined")
- {
- model.hideNone = self.options.removeDefaultNone;
- }
-
- callback(model);
- });
- },
-
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- if (this.schema && this.schema["enum"])
- {
- return this.schema["enum"];
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function(val)
- {
- var _this = this;
- if (Alpaca.isArray(val))
- {
- $.each(val, function(index, itemVal) {
- $.each(_this.selectOptions, function(index2, selectOption) {
-
- if (selectOption.value === itemVal)
- {
- val[index] = selectOption.value;
- }
-
- });
- });
- }
- else
- {
- $.each(this.selectOptions, function(index, selectOption) {
-
- if (selectOption.value === val)
- {
- val = selectOption.value;
- }
-
- });
- }
- return val;
- },
-
- /**
- * @see Alpaca.ControlField#beforeRenderControl
- */
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.options.dataSource)
- {
- self.selectOptions = [];
-
- var completionFunction = function()
- {
- self.schema.enum = [];
- self.options.optionLabels = [];
-
- for (var i = 0; i < self.selectOptions.length; i++)
- {
- self.schema.enum.push(self.selectOptions[i].value);
- self.options.optionLabels.push(self.selectOptions[i].text);
- }
-
- // push back to model
- model.selectOptions = self.selectOptions;
-
- callback();
- };
-
- if (Alpaca.isFunction(self.options.dataSource))
- {
- self.options.dataSource.call(self, function(values) {
-
- if (Alpaca.isArray(values))
- {
- for (var i = 0; i < values.length; i++)
- {
- if (typeof(values[i]) === "string")
- {
- self.selectOptions.push({
- "text": values[i],
- "value": values[i]
- });
- }
- else if (Alpaca.isObject(values[i]))
- {
- self.selectOptions.push(values[i]);
- }
- }
-
- completionFunction();
- }
- else if (Alpaca.isObject(values))
- {
- for (var k in values)
- {
- self.selectOptions.push({
- "text": k,
- "value": values[k]
- });
- }
-
- completionFunction();
- }
- else
- {
- completionFunction();
- }
- });
- }
- else if (Alpaca.isUri(self.options.dataSource))
- {
- $.ajax({
- url: self.options.dataSource,
- type: "get",
- dataType: "json",
- success: function(jsonDocument) {
-
- var ds = jsonDocument;
- if (self.options.dsTransformer && Alpaca.isFunction(self.options.dsTransformer))
- {
- ds = self.options.dsTransformer(ds);
- }
-
- if (ds)
- {
- if (Alpaca.isObject(ds))
- {
- // for objects, we walk through one key at a time
- // the insertion order is the order of the keys from the map
- // to preserve order, consider using an array as below
- $.each(ds, function(key, value) {
- self.selectOptions.push({
- "value": key,
- "text": value
- });
- });
-
- completionFunction();
- }
- else if (Alpaca.isArray(ds))
- {
- // for arrays, we walk through one index at a time
- // the insertion order is dictated by the order of the indices into the array
- // this preserves order
- $.each(ds, function(index, value) {
- self.selectOptions.push({
- "value": value.value,
- "text": value.text
- });
- });
-
- completionFunction();
- }
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
-
- self.errorCallback({
- "message":"Unable to load data from uri : " + _this.options.dataSource,
- "stage": "DATASOURCE_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- });
- }
- else if (Alpaca.isArray(self.options.dataSource))
- {
- for (var i = 0; i < self.options.dataSource.length; i++)
- {
- if (typeof(self.options.dataSource[i]) === "string")
- {
- self.selectOptions.push({
- "text": self.options.dataSource[i],
- "value": self.options.dataSource[i]
- });
- }
- else if (Alpaca.isObject(self.options.dataSource[i]))
- {
- self.selectOptions.push(self.options.dataSource[i]);
- }
- }
-
- completionFunction();
- }
- else
- {
- callback();
- }
- }
- else
- {
- callback();
- }
-
- });
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumeration",
- "description": "List of field value options",
- "type": "array",
- "required": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "optionLabels": {
- "title": "Option Labels",
- "description": "Labels for options. It can either be a map object or an array field that maps labels to items defined by enum schema property one by one.",
- "type": "array"
- },
- "dataSource": {
- "title": "Option Datasource",
- "description": "Datasource for generating list of options. This can be a string or a function. If a string, it is considered to be a URI to a service that produces a object containing key/value pairs or an array of elements of structure {'text': '', 'value': ''}. This can also be a function that is called to produce the same list.",
- "type": "string"
- },
- "removeDefaultNone": {
- "title": "Remove Default None",
- "description": "If true, the default 'None' option will not be shown.",
- "type": "boolean",
- "default": false
- },
- "noneLabel": {
- "title": "None Label",
- "description": "The label to use for the 'None' option in a list (select, radio or otherwise).",
- "type": "string",
- "default": "None"
- },
- "hideNone": {
- "title": "Hide None",
- "description": "Whether to hide the None option from a list (select, radio or otherwise). This will be true if the field is required and false otherwise.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "optionLabels": {
- "itemLabel":"Label",
- "type": "array"
- },
- "dataSource": {
- "type": "text"
- },
- "removeDefaultNone": {
- "type": "checkbox",
- "rightLabel": "Remove Default None"
- },
- "noneLabel": {
- "type": "text"
- },
- "hideNone": {
- "type": "checkbox",
- "rightLabel": "Hide the 'None' option from the list"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-})(jQuery);
-
-(function($){
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.RadioField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.RadioField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "radio";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.options.name)
- {
- this.name = this.options.name;
- }
- else if (!this.name)
- {
- this.name = this.getId() + "-name";
- }
-
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.emptySelectFirst))
- {
- this.options.emptySelectFirst = false;
- }
-
- // assume vertical orientation
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.vertical))
- {
- this.options.vertical = true;
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var val = null;
-
- $(this.control).find(":checked").each(function() {
- val = $(this).val();
-
- val = self.ensureProperType(val);
- });
-
- return val;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- var self = this;
-
- // clear all
- $(this.control).find("input").each(function() {
- Alpaca.checked($(this), null);
- });
-
- // mark selected value
- if (typeof(val) != "undefined")
- {
- Alpaca.checked($(self.control).find("input[value=\"" + val + "\"]"), "checked");
- }
-
- // if none selected and "emptySelectFirst", then select
- if (this.options.emptySelectFirst)
- {
- if ($(this.control).find("input:checked").length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio").first(), "checked");
- }
- }
-
- this.base(val);
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- var inputs = $(this.control).find("input");
-
- inputs.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- inputs.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
- model.removeDefaultNone = self.options.removeDefaultNone;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
-
- if ($("input:radio:checked", self.control).length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio[value=\"" + self.data + "\"]"), "checked");
- }
- }
-
- // stack radio selectors vertically
- if (self.options.vertical)
- {
- $(self.control).css("display", "block");
- }
- else
- {
- $(self.control).css("display", "inline-block");
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.ControlField#onClick
- */
- onClick: function(e)
- {
- this.base(e);
-
- var self = this;
-
- var val = $(e.currentTarget).find("input").val();
- if (typeof(val) != "undefined")
- {
- self.setValue(val);
- self.refreshValidationState();
- }
-
- /*
- Alpaca.later(25, this, function(){
- var v = self.getValue();
- self.setValue(v);
- self.refreshValidationState();
- });
- */
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Radio Group Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Radio Group Field with list of options.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function()
- {
- return Alpaca.merge(this.base(),{
- "properties": {
- "name": {
- "title": "Field name",
- "description": "Field name.",
- "type": "string"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "vertical": {
- "title": "Position the radio selector items vertically",
- "description": "By default, radio controls are stacked vertically. Set to false if you'd like radio controls to lay out horizontally.",
- "type": "boolean",
- "default": true
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("radio", Alpaca.Fields.RadioField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SelectField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.SelectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function()
- {
- return "select";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- if (this.control && this.control.length > 0)
- {
- var val = this._getControlVal(true);
- if (typeof(val) === "undefined")
- {
- val = this.data;
- }
-
- return this.base(val);
- }
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- if (Alpaca.isArray(val))
- {
- if (!Alpaca.compareArrayContent(val, this.getValue()))
- {
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- else
- {
- if (val !== this.getValue())
- {
- /*
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
- */
- if (this.control && typeof(val) != "undefined" && val != null)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- },
-
- /**
- * @see Alpaca.ListField#getEnum
- */
- getEnum: function()
- {
- if (this.schema)
- {
- if (this.schema["enum"])
- {
- return this.schema["enum"];
- }
- else if (this.schema["type"] && this.schema["type"] === "array" && this.schema["items"] && this.schema["items"]["enum"])
- {
- return this.schema["items"]["enum"];
- }
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- if (self.options.multiple)
- {
- var button = this.control.parent().find("button.multiselect");
-
- button.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- button.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- }
- },
-
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.schema["type"] && self.schema["type"] === "array")
- {
- self.options.multiple = true;
- }
-
- callback();
-
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (Alpaca.isUndefined(self.data) && self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
- }
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the state of the control
- if (self.data)
- {
- self.setValue(self.data);
- }
-
- // if we are in multiple mode and the bootstrap multiselect plugin is available, bind it in
- if (self.options.multiple && $.fn.multiselect)
- {
- var settings = null;
- if (self.options.multiselect) {
- settings = self.options.multiselect;
- }
- else
- {
- settings = {};
- }
- if (!settings.nonSelectedText)
- {
- settings.nonSelectedText = "None";
- if (self.options.noneLabel)
- {
- settings.nonSelectedText = self.options.noneLabel;
- }
- }
- if (self.options.hideNone)
- {
- delete settings.nonSelectedText;
- }
-
- $(self.getControlEl()).multiselect(settings);
- }
-
- callback();
-
- });
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var _this = this;
-
- if (this.schema["enum"])
- {
- var val = this.data;
-
- if (!this.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- if (this.options.multiple)
- {
- var isValid = true;
-
- if (!val)
- {
- val = [];
- }
-
- if (!Alpaca.isArray(val) && !Alpaca.isObject(val))
- {
- val = [val];
- }
-
- $.each(val, function(i,v) {
-
- if ($.inArray(v, _this.schema["enum"]) <= -1)
- {
- isValid = false;
- return false;
- }
-
- });
-
- return isValid;
- }
- else
- {
- return ($.inArray(val, this.schema["enum"]) > -1);
- }
- }
- else
- {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- _this.refreshValidationState();
- });
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if ($(":selected",this.control).length < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if ($(":selected",this.control).length > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Select Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Select Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multiple": {
- "title": "Mulitple Selection",
- "description": "Allow multiple selection if true.",
- "type": "boolean",
- "default": false
- },
- "size": {
- "title": "Displayed Options",
- "description": "Number of options to be shown.",
- "type": "number"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "multiselect": {
- "title": "Multiselect Plugin Settings",
- "description": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multiple": {
- "rightLabel": "Allow multiple selection ?",
- "helper": "Allow multiple selection if checked",
- "type": "checkbox"
- },
- "size": {
- "type": "integer"
- },
- "emptySelectFirst": {
- "type": "checkbox",
- "rightLabel": "Empty Select First"
- },
- "multiselect": {
- "type": "object",
- "rightLabel": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("select", Alpaca.Fields.SelectField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.NumberField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.NumberField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "number";
- //this.inputType = "number";
- // TODO: we can't do this because Chrome screws up it's handling of number type
- // and prevents us from validating properly
- // @see http://stackoverflow.com/questions/16420828/jquery-val-refuses-to-return-non-numeric-input-from-a-number-field-under-chrome
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "number";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var val = this._getControlVal(true);
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseFloat(val);
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateNumber();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotANumber"),
- "status": status
- };
-
- status = this._validateDivisibleBy();
- valInfo["stringDivisibleBy"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringDivisibleBy"), [this.schema.divisibleBy]),
- "status": status
- };
-
- status = this._validateMaximum();
- valInfo["stringValueTooLarge"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMaximum) {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLargeExclusive"), [this.schema.maximum]);
- } else {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLarge"), [this.schema.maximum]);
- }
- }
-
- status = this._validateMinimum();
- valInfo["stringValueTooSmall"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMinimum) {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmallExclusive"), [this.schema.minimum]);
- } else {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmall"), [this.schema.minimum]);
- }
- }
-
- status = this._validateMultipleOf();
- valInfo["stringValueNotMultipleOf"] = {
- "message": "",
- "status": status
- };
- if (!status)
- {
- valInfo["stringValueNotMultipleOf"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueNotMultipleOf"), [this.schema.multipleOf]);
- }
-
- // hand back a true/false
- return baseStatus && valInfo["stringNotANumber"]["status"] && valInfo["stringDivisibleBy"]["status"] && valInfo["stringValueTooLarge"]["status"] && valInfo["stringValueTooSmall"]["status"] && valInfo["stringValueNotMultipleOf"]["status"];
- },
-
- /**
- * Validates if it is a float number.
- * @returns {Boolean} true if it is a float number
- */
- _validateNumber: function() {
-
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid number format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.number, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * Validates divisibleBy constraint.
- * @returns {Boolean} true if it passes the divisibleBy constraint.
- */
- _validateDivisibleBy: function() {
- var floatValue = this.getValue();
- if (!Alpaca.isEmpty(this.schema.divisibleBy)) {
-
- // mod
- if (floatValue % this.schema.divisibleBy !== 0)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the maximum constraint.
- */
- _validateMaximum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.maximum)) {
- if (floatValue > this.schema.maximum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMaximum)) {
- if (floatValue == this.schema.maximum && this.schema.exclusiveMaximum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the minimum constraint.
- */
- _validateMinimum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.minimum)) {
- if (floatValue < this.schema.minimum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMinimum)) {
- if (floatValue == this.schema.minimum && this.schema.exclusiveMinimum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates multipleOf constraint.
- * @returns {Boolean} true if it passes the multipleOf constraint.
- */
- _validateMultipleOf: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.multipleOf)) {
- if (floatValue && this.schema.multipleOf !== 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "number";
- },
-
- /* builder_helpers */
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "Property value must be a multiple of the multipleOf schema property such that division by this value yields an interger (mod zero).",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "number"
- },
- "exclusiveMinimum": {
- "title": "Exclusive Minimum",
- "description": "Property value can not equal the number defined by the minimum schema property.",
- "type": "boolean",
- "default": false
- },
- "exclusiveMaximum": {
- "title": "Exclusive Maximum",
- "description": "Property value can not equal the number defined by the maximum schema property.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "The value must be a integral multiple of the property",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property",
- "type": "number"
- },
- "exclusiveMinimum": {
- "rightLabel": "Exclusive minimum ?",
- "helper": "Field value must be greater than but not equal to this number if checked",
- "type": "checkbox"
- },
- "exclusiveMaximum": {
- "rightLabel": "Exclusive Maximum ?",
- "helper": "Field value must be less than but not equal to this number if checked",
- "type": "checkbox"
- }
- }
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Number Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for float numbers.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringValueTooSmall": "The minimum value for this field is {0}",
- "stringValueTooLarge": "The maximum value for this field is {0}",
- "stringValueTooSmallExclusive": "Value of this field must be greater than {0}",
- "stringValueTooLargeExclusive": "Value of this field must be less than {0}",
- "stringDivisibleBy": "The value must be divisible by {0}",
- "stringNotANumber": "This value is not a number.",
- "stringValueNotMultipleOf": "This value is not a multiple of {0}"
- });
- Alpaca.registerFieldClass("number", Alpaca.Fields.NumberField);
- Alpaca.registerDefaultSchemaFieldMapping("number", "number");
-
-})(jQuery);
-
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ArrayField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ArrayField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "array";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = Alpaca.isEmpty(this.view.toolbarStyle) ? "button" : this.view.toolbarStyle;
- }
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = "button";
- }
-
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = Alpaca.isEmpty(this.view.actionbarStyle) ? "top" : this.view.actionbarStyle;
- }
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = "top";
- }
-
- // determine whether we are using "ruby on rails" compatibility mode
- this.options.rubyrails = false;
- if (this.parent && this.parent.options && this.parent.options.form && this.parent.options.form.attributes)
- {
- if (!Alpaca.isEmpty(this.parent.options.form.attributes.rubyrails))
- {
- this.options.rubyrails = true;
- }
- }
-
- if (!this.options.items)
- {
- this.options.items = {};
- }
-
- var toolbarSticky = true;
-
- if (!Alpaca.isEmpty(this.view.toolbarSticky))
- {
- toolbarSticky = this.view.toolbarSticky;
- }
-
- if (!Alpaca.isEmpty(this.options.toolbarSticky))
- {
- toolbarSticky = this.options.toolbarSticky;
- }
-
- this.options.toolbarSticky = toolbarSticky;
-
- // Enable forceRevalidation option so that any change in children will trigger parent's revalidation.
- if (this.schema.items && this.schema.uniqueItems)
- {
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
- }
-
- if (typeof(this.data) == "undefined")
- {
- this.data = [];
- }
-
- if (this.data == null)
- {
- this.data = [];
- }
-
- if ("" == this.data)
- {
- this.data = [];
- }
-
- if (Alpaca.isString(this.data))
- {
- // assume to be a serialized array or object, convert
- try
- {
- var parsedJSON = Alpaca.parseJSON(this.data);
-
- if (!Alpaca.isArray(parsedJSON) && !Alpaca.isObject(parsedJSON))
- {
- Alpaca.logWarn("ArrayField parsed string data but it was not an array: " + this.data);
- return;
- }
-
- this.data = parsedJSON;
- }
- catch (e)
- {
- // assume just a string value, put into array
- this.data = [this.data];
- }
- }
-
- if (!Alpaca.isArray(this.data) && !Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ArrayField data is not an array: " + JSON.stringify(this.data, null, " "));
- return;
- }
-
- //
- // ACTIONS
- //
- var applyAction = function(actions, key, actionConfig) {
- var action = self.findAction(actions, key);
- if (!action) {
- action = {
- "core": true
- };
- actions.push(action);
- }
- for (var k in actionConfig) {
- action[k] = actionConfig[k];
- }
- };
- var cleanupActions = function(actions, showLabels) {
- var i = 0;
- do {
-
- // assume enabled by default
- if (typeof(actions[i].enabled) === "undefined") {
- actions[i].enabled = true;
- }
-
- // hide label if global disable
- if (!showLabels) {
- delete actions[i].label;
- }
-
- if (!actions[i].enabled) {
- actions.splice(i, 1);
- } else {
- i++;
- }
-
- } while (i < actions.length);
-
- // sort so that core actions appear first
- actions.sort(function(a, b) {
- if (a.core && !b.core) {
- return -1;
- }
- if (!a.core && b.core) {
- return 1;
- }
- return 0;
- });
- };
-
- // set up default actions for the top array toolbar
- self.toolbar = {};
- if (self.options.toolbar)
- {
- for (var k in self.options.toolbar) {
- self.toolbar[k] = self.options.toolbar[k];
- }
- }
- if (typeof(self.toolbar.showLabels) === "undefined") {
- self.toolbar.showLabels = false;
- }
- if (!self.toolbar.actions) {
- self.toolbar.actions = [];
- }
- applyAction(self.toolbar.actions, "add", {
- "label": "Add New Item",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action)
- {
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(0, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
- }
- });
- cleanupActions(self.toolbar.actions, self.toolbar.showLabels);
-
- // determine which actions to add into the per-item actionbar
- self.actionbar = {};
- if (self.options.actionbar)
- {
- for (var k2 in self.options.actionbar) {
- self.actionbar[k2] = self.options.actionbar[k2];
- }
- }
- if (typeof(self.actionbar.showLabels) === "undefined") {
- self.actionbar.showLabels = false;
- }
- if (!self.actionbar.actions) {
- self.actionbar.actions = [];
- }
- applyAction(self.actionbar.actions, "add", {
- "label": "Add",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action, itemIndex) {
-
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(itemIndex + 1, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
-
- }
- });
- applyAction(self.actionbar.actions, "remove", {
- "label": "Remove",
- "action": "remove",
- "iconClass": self.view.getStyle("removeIcon"),
- "click": function(key, action, itemIndex) {
-
- self.removeItem(itemIndex, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "up", {
- "label": "Up",
- "action": "up",
- "iconClass": self.view.getStyle("upIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex - 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "down", {
- "label": "Down",
- "action": "down",
- "iconClass": self.view.getStyle("downIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex + 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- cleanupActions(self.actionbar.actions, self.actionbar.showLabels);
-
- var len = this.data.length;
- var data = $.extend(true, {}, this.data);
- data.length = len;
-
- this.data = Array.prototype.slice.call(data);
- },
-
- /**
- * Picks apart the array and set onto child fields.
- * @see Alpaca.ContainerField#setup
- */
- setValue: function(data)
- {
- var self = this;
-
- if (!data || !Alpaca.isArray(data))
- {
- return;
- }
-
- // set fields
- var i = 0;
- do
- {
- if (i < self.children.length)
- {
- var childField = self.children[i];
-
- if (data.length > i)
- {
- childField.setValue(data[i]);
- i++;
- }
- else
- {
- self.removeItem(i);
- }
- }
- }
- while (i < self.children.length);
-
- // if the number of items in the data is greater than the number of existing child elements
- // then we need to add the new fields
- if (i < data.length)
- {
- self.resolveItemSchemaOptions(function(schema, options) {
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for item: " + i);
- }
-
- // waterfall functions
- var funcs = [];
-
- while (i < data.length)
- {
- var f = (function(i, data)
- {
- return function(callback)
- {
- self.addItem(i, schema, options, data[i], function() {
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
- })(i, data[i]);
-
- funcs.push(f);
-
- i++;
- }
-
- Alpaca.series(funcs, function() {
- // nothing
- });
- });
- }
-
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we're empty and we're also not required, then we hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // otherwise, construct an array and had it back
- var o = [];
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
-
- if (typeof(v) !== "undefined")
- {
- o.push(v);
- }
- }
- return o;
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var self = this;
-
- var items = [];
-
- if (self.data)
- {
- // all items within the array have the same schema and options
- // so we only need to load this once
- self.resolveItemSchemaOptions(function(schema, options) {
-
- // waterfall functions
- var funcs = [];
- for (var index = 0; index < self.data.length; index++)
- {
- var value = self.data[index];
-
- var pf = (function(index, value)
- {
- return function(callback)
- {
- self.createItem(index, schema, options, value, function(item) {
-
- items.push(item);
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
-
- })(index, value);
-
- funcs.push(pf);
- }
-
- Alpaca.series(funcs, function(err) {
- callback(items);
- });
-
- });
- }
- else
- {
- callback(items);
- }
- },
-
- /**
- * Workhorse method for createItem.
- *
- * @param index
- * @param itemSchema
- * @param itemOptions
- * @param itemData
- * @param postRenderCallback
- * @return {*}
- * @private
- */
- createItem: function(index, itemSchema, itemOptions, itemData, postRenderCallback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render": function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // setup item path
- fieldControl.path = self.path + "[" + index + "]";
- //fieldControl.nameCalculated = true;
- fieldControl.render(null, function() {
-
- // remember the control
- self.refreshValidationState();
- self.updatePathAndName();
-
- // trigger update on the parent array
- self.triggerUpdate();
-
- if (cb)
- {
- cb();
- }
- });
- },
- "postRender": function(control)
- {
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- // PR: https://github.com/gitana/alpaca/pull/124
- if (Alpaca.isFunction(self.options.items.postRender))
- {
- self.options.items.postRender.call(control, insertionPointEl);
- }
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- }
- },
-
- /**
- * Determines the schema and options to utilize for items within this array.
- *
- * @param callback
- */
- resolveItemSchemaOptions: function(callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedItemSchema, resolvedItemOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedItemOptions.readonly = true;
- }
-
- callback(resolvedItemSchema, resolvedItemOptions, circular);
- };
-
- var itemOptions;
- // legacy support for options.fields.item
- if (!itemOptions && _this.options && _this.options.fields && _this.options.fields.item) {
- itemOptions = _this.options.fields.item;
- }
- if (!itemOptions && _this.options && _this.options.items) {
- itemOptions = _this.options.items;
- }
- var itemSchema;
- if (_this.schema && _this.schema.items) {
- itemSchema = _this.schema.items;
- }
-
- // handle $ref
- if (itemSchema && itemSchema["$ref"])
- {
- var referenceId = itemSchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalItemSchema = itemSchema;
- var originalItemOptions = itemOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(itemSchema, itemOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedItemSchema = {};
- if (originalItemSchema) {
- Alpaca.mergeObject(resolvedItemSchema, originalItemSchema);
- }
- if (itemSchema)
- {
- Alpaca.mergeObject(resolvedItemSchema, itemSchema);
- }
- delete resolvedItemSchema.id;
-
- var resolvedItemOptions = {};
- if (originalItemOptions) {
- Alpaca.mergeObject(resolvedItemOptions, originalItemOptions);
- }
- if (itemOptions)
- {
- Alpaca.mergeObject(resolvedItemOptions, itemOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedItemSchema, resolvedItemOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(itemSchema, itemOptions);
- });
- }
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateUniqueItems();
- valInfo["valueNotUnique"] = {
- "message": status ? "" : this.view.getMessage("valueNotUnique"),
- "status": status
- };
-
- status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["valueNotUnique"]["status"] && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- },
-
- /**
- * Validates if the number of items has been reached to maxItems.
- * @returns {Boolean} true if the number of items has been reached to maxItems
- */
- _validateEqualMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() >= this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if the number of items has been reached to minItems.
- * @returns {Boolean} true if number of items has been reached to minItems
- */
- _validateEqualMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() <= this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if all items are unique.
- * @returns {Boolean} true if all items are unique.
- */
- _validateUniqueItems: function()
- {
- if (this.schema.items && this.schema.uniqueItems)
- {
- var hash = {};
- for (var i = 0, l = this.children.length; i < l; ++i)
- {
- if (!hash.hasOwnProperty(this.children[i]))
- {
- hash[this.children[i]] = true;
- }
- else
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- findAction: function(actionsArray, actionKey)
- {
- var action = null;
-
- $.each(actionsArray, function(i, v) {
- if (v.action == actionKey) // jshint ignore:line
- {
- action = v;
- }
- });
-
- return action;
- },
-
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
-
- });
- },
-
- /*
- afterApplyCreatedItems: function(model, callback)
- {
- var self = this;
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
- },
- */
-
- /**
- * Returns number of children.
- */
- getSize: function() {
- return this.children.length;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updatePathAndName: function()
- {
- var self = this;
-
- var updateChildrenPathAndName = function(parent)
- {
- if (parent.children)
- {
- $.each(parent.children, function(i, v) {
-
- if (parent.prePath && Alpaca.startsWith(v.path,parent.prePath))
- {
- v.prePath = v.path;
- v.path = v.path.replace(parent.prePath,parent.path);
- }
-
- // re-calculate name
- if (parent.preName && Alpaca.startsWith(v.name, parent.preName))
- {
- v.preName = v.name;
- v.name = v.name.replace(parent.preName, parent.name);
- if (v.field)
- {
- $(v.field).attr('name', v.name);
- }
- }
-
- updateChildrenPathAndName(v);
- });
- }
- };
-
- if (this.children && this.children.length > 0)
- {
- $.each(this.children, function(i, v) {
-
- var idx = v.path.lastIndexOf('/');
- var lastSegment = v.path.substring(idx+1);
- if (lastSegment.indexOf("[") < 0 && lastSegment.indexOf("]") < 0)
- {
- lastSegment = lastSegment.substring(lastSegment.indexOf("[") + 1, lastSegment.indexOf("]"));
- }
-
- if (lastSegment !== i)
- {
- v.prePath = v.path;
- v.path = v.path.substring(0, idx) + "/[" + i + "]";
- }
-
- // re-calculate name
- if (v.nameCalculated)
- {
- v.preName = v.name;
-
- if (v.parent && v.parent.name && v.path)
- {
- v.name = v.parent.name + "_" + i;
- }
- else
- {
- if (v.path)
- {
- v.name = v.path.replace(/\//g, "").replace(/\[/g, "_").replace(/\]/g, "");
- }
- }
-
- if (this.parent.options.rubyrails )
- {
- $(v.field).attr('name', v.parent.name);
- }
- else
- {
- $(v.field).attr('name', v.name);
- }
-
- }
-
- if (!v.prePath)
- {
- v.prePath = v.path;
- }
-
- updateChildrenPathAndName(v);
- });
- }
- },
-
- /**
- * Updates the status of array item action toolbar buttons.
- */
- updateToolbars: function()
- {
- var self = this;
-
- // if we're in display mode, we do not do this
- if (this.view.type === "display")
- {
- return;
- }
-
- // if we're in readonly mode, don't do this
- if (this.schema.readonly)
- {
- return;
- }
-
- // fire callbacks to view to remove and create toolbar
- if (self.toolbar)
- {
- self.fireCallback("arrayToolbar", true);
- self.fireCallback("arrayToolbar");
- }
-
- // fire callbacks to view to remove and create an actionbar for each item
- if (self.actionbar)
- {
- self.fireCallback("arrayActionbars", true);
- self.fireCallback("arrayActionbars");
- }
-
- //
- // TOOLBAR
- //
-
- var toolbarEl = $(this.getFieldEl()).find(".alpaca-array-toolbar[data-alpaca-array-toolbar-field-id='" + self.getId() + "']");
- if (this.children.length > 0)
- {
- // hide toolbar
- $(toolbarEl).hide();
- }
- else
- {
- // show toolbar
- $(toolbarEl).show();
-
- // CLICK: array toolbar buttons
- $(toolbarEl).find("[data-alpaca-array-toolbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-toolbar-action");
- var action = self.findAction(self.toolbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action);
- });
- }
- });
- }
-
-
- //
- // ACTIONBAR
- //
-
- // if we're not using the "sticky" toolbar, then show and hide the item action buttons when hovered
- if (!this.options.toolbarSticky)
- {
- // find each item
- var items = this.getFieldEl().find(".alpaca-container-item");
- $(items).each(function(itemIndex) {
-
- // find the actionbar for this item
- // find from containerItemEl
- var actionbarEl = $(self.containerItemEl).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "'][data-alpaca-array-actionbar-item-index='" + itemIndex + "']");
- if (actionbarEl && actionbarEl.length > 0)
- {
- $(this).hover(function() {
- $(actionbarEl).show();
- }, function() {
- $(actionbarEl).hide();
- });
-
- $(actionbarEl).hide();
- }
- });
- }
- else
- {
- // otherwise, always show the actionbars
- $(self.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "']").show();
- }
-
- // CLICK: actionbar buttons
- var actionbarEls = $(this.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-parent-field-id='" + self.getId() + "']");
- $(actionbarEls).each(function() {
-
- var targetIndex = $(this).attr("data-alpaca-array-actionbar-item-index");
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- // bind button click handlers
- $(this).find("[data-alpaca-array-actionbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-actionbar-action");
- var action = self.findAction(self.actionbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action, targetIndex);
- });
- }
- });
-
- // if we're at max capacity, disable "add" buttons
- if (self._validateEqualMaxItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
-
- // if we're at min capacity, disable "remove" buttons
- if (self._validateEqualMinItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
- });
- // first actionbar has its "move up" button disabled
- $(actionbarEls).first().find("[data-alpaca-array-actionbar-action='up']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- // last actionbar has its "move down" button disabled
- $(actionbarEls).last().find("[data-alpaca-array-actionbar-action='down']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
-
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- doResolveItemContainer: function()
- {
- var self = this;
-
- return $(self.container);
- },
-
- doAddItem: function(index, item)
- {
- var self = this;
-
- var addItemContainer = self.doResolveItemContainer();
-
- // insert into dom
- if (index === 0)
- {
- // insert first into container
- $(addItemContainer).append(item.containerItemEl);
- }
- else
- {
- // insert at a specific index
- var existingElement = addItemContainer.children("[data-alpaca-container-item-index='" + (index-1) + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(item.containerItemEl);
- }
- }
-
- self.doAfterAddItem(item);
- },
-
- doAfterAddItem: function(item)
- {
-
- },
-
- /**
- * Adds an item to the array.
- *
- * This gets called from the toolbar when items are added via the user interface. The method can also
- * be called programmatically to insert items on the fly.
- *
- * @param {Integer} index the index where the item should be inserted
- * @param {Object} schema the json schema
- * @param {Object} options the json options
- * @param {Any} data the data for the newly inserted item
- * @param [Function] callback called after the child is added
- */
- addItem: function(index, schema, options, data, callback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- self.createItem(index, schema, options, data, function(item) {
-
- // register the child
- self.registerChild(item, index);
-
- // insert into dom
- self.doAddItem(index, item);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- }
- },
-
- doRemoveItem: function(childIndex)
- {
- var self = this;
-
- var removeItemContainer = self.doResolveItemContainer();
-
- removeItemContainer.children(".alpaca-container-item[data-alpaca-container-item-index='" + childIndex + "']").remove();
- },
-
- /**
- * Removes an item from the array.
- *
- * This gets called automatically from setValue() when the number of items being set is less than the number
- * of field elements.
-
- * @param {Number} childIndex index of the child to be removed
- * @param [Function] callback called after the child is removed
- */
- removeItem: function(childIndex, callback)
- {
- var self = this;
-
- if (this._validateEqualMinItems())
- {
- // unregister the child
- self.unregisterChild(childIndex);
-
- // remove itemContainerEl from DOM
- self.doRemoveItem(childIndex);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- }
- },
-
- /**
- * Dynamically moves a child to a new index in the array.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to be moved to
- * @param {Boolean} animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- if (sourceIndex === targetIndex)
- {
- // nothing to do
- return;
- }
-
- //console.log("Source: " + sourceIndex + ", Target: " + targetIndex);
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- var parentFieldId = self.getId();
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + sourceIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
- var targetContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + targetIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- var duration = 0;
- if (animate)
- {
- duration = 500;
- }
-
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, duration, function() {
- onComplete();
- });
- },
-
- /**
- * @see Alpaca.ContainerField#getType
- */
- getType: function() {
- return "array";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.ContainerField#getTitle
- */
- getTitle: function() {
- return "Array Field";
- },
-
- /**
- * @see Alpaca.ContainerField#getDescription
- */
- getDescription: function() {
- return "Field for list of items with same data type or structure.";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "items": {
- "title": "Array Items",
- "description": "Schema for array items.",
- "type": "object",
- "properties": {
- "minItems": {
- "title": "Minimum Items",
- "description": "Minimum number of items.",
- "type": "number"
- },
- "maxItems": {
- "title": "Maximum Items",
- "description": "Maximum number of items.",
- "type": "number"
- },
- "uniqueItems": {
- "title": "Items Unique",
- "description": "Item values should be unique if true.",
- "type": "boolean",
- "default": false
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "items": {
- "type": "object",
- "fields": {
- "minItems": {
- "type": "integer"
- },
- "maxItems": {
- "type": "integer"
- },
- "uniqueItems": {
- "type": "checkbox"
- }
- }
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var properties = {
- "properties": {
- "toolbarSticky": {
- "title": "Sticky Toolbar",
- "description": "Array item toolbar will be aways on if true.",
- "type": "boolean",
- "default": false
- },
- "toolbarStyle": {
- "title": "Toolbar Style",
- "description": "The kind of top-level toolbar to render for the array field. Either 'button' or 'link'.",
- "type": "string",
- "default": "button"
- },
- "actionbarStyle": {
- "title": "Actionbar Style",
- "description": "The kind of actionbar to render for each item in the array. Either 'top', 'bottom', 'left', or 'right'.",
- "type": "string",
- "default": "top"
- },
- "toolbar": {
- "type": "object",
- "title": "Toolbar Configuration",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Toolbar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- },
- "actionbar": {
- "type": "object",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Actions Bar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "toolbarSticky": {
- "type": "checkbox"
- },
- "items": {
- "type": "object",
- "fields": {
- }
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "notEnoughItems": "The minimum number of items is {0}",
- "tooManyItems": "The maximum number of items is {0}",
- "valueNotUnique": "Values are not unique",
- "notAnArray": "This value is not an Array"
- });
- Alpaca.registerFieldClass("array", Alpaca.Fields.ArrayField);
- Alpaca.registerDefaultSchemaFieldMapping("array", "array");
-
-})(jQuery);
-
-/*jshint -W004 */ // duplicate variables
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ObjectField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ObjectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "object";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- var x = self.resolveContainerItemTemplateType();
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
-
- if (this.data === "")
- {
- return;
- }
-
- if (!Alpaca.isObject(this.data))
- {
- if (!Alpaca.isString(this.data))
- {
- return;
- }
- else
- {
- try
- {
- this.data = Alpaca.parseJSON(this.data);
- if (!Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ObjectField parsed data but it was not an object: " + JSON.stringify(this.data));
- return;
- }
- }
- catch (e)
- {
- return;
- }
- }
- }
- },
-
- /**
- * Picks apart the data object and set onto child fields.
- *
- * @see Alpaca.Field#setValue
- */
- setValue: function(data)
- {
- if (!data)
- {
- data = {};
- }
-
- // if not an object by this point, we don't handle it
- if (!Alpaca.isObject(data))
- {
- return;
- }
-
- // sort existing fields by property id
- var existingFieldsByPropertyId = {};
- for (var fieldId in this.childrenById)
- {
- var propertyId = this.childrenById[fieldId].propertyId;
- existingFieldsByPropertyId[propertyId] = this.childrenById[fieldId];
- }
-
- // new data mapped by property id
- var newDataByPropertyId = {};
- for (var k in data)
- {
- if (data.hasOwnProperty(k))
- {
- newDataByPropertyId[k] = data[k];
- }
- }
-
- // walk through new property ids
- // if a field exists, set value onto it and remove from newDataByPropertyId and existingFieldsByPropertyId
- // if a field doesn't exist, let it remain in list
- for (var propertyId in newDataByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- if (field)
- {
- field.setValue(newDataByPropertyId[propertyId]);
-
- delete existingFieldsByPropertyId[propertyId];
- delete newDataByPropertyId[propertyId];
- }
- }
-
- // anything left in existingFieldsByPropertyId describes data that is missing, null or empty
- // we null out those values
- for (var propertyId in existingFieldsByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- field.setValue(null);
- }
-
- // anything left in newDataByPropertyId is new stuff that we need to add
- // the object field doesn't support this since it runs against a schema
- // so we drop this off
- },
-
- /**
- * Reconstructs the data object from the child fields.
- *
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back empty object
- if (this.children.length === 0 && !this.isRequired())
- {
- return {};
- }
-
- // otherwise, hand back an object with our child properties in it
- var o = {};
-
- // walk through all of the properties object
- // for each property, we insert it into a JSON object that we'll hand back as the result
-
- // if the property has dependencies, then we evaluate those dependencies first to determine whether the
- // resulting property should be included
-
- for (var i = 0; i < this.children.length; i++)
- {
- // the property key and vlaue
- var propertyId = this.children[i].propertyId;
- var fieldValue = this.children[i].getValue();
-
- if (typeof(fieldValue) !== "undefined")
- {
- if (this.determineAllDependenciesValid(propertyId))
- {
- var assignedValue = null;
-
- if (typeof(fieldValue) === "boolean")
- {
- assignedValue = (fieldValue? true: false);
- }
- else if (Alpaca.isArray(fieldValue) || Alpaca.isObject(fieldValue) || Alpaca.isNumber(fieldValue))
- {
- assignedValue = fieldValue;
- }
- else if (fieldValue)
- {
- assignedValue = fieldValue;
- }
-
- if (assignedValue !== null)
- {
- o[propertyId] = assignedValue;
- }
- }
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- // Generates wizard if requested
- if (self.isTopLevel())
- {
- if (self.view)
- {
- self.wizardConfigs = self.view.getWizard();
- if (typeof(self.wizardConfigs) != "undefined")
- {
- if (!self.wizardConfigs || self.wizardConfigs === true)
- {
- self.wizardConfigs = {};
- }
- }
-
- var layoutTemplateDescriptor = self.view.getLayout().templateDescriptor;
- if (self.wizardConfigs && Alpaca.isObject(self.wizardConfigs))
- {
- if (!layoutTemplateDescriptor || self.wizardConfigs.bindings)
- {
- // run the automatic wizard
- self.autoWizard();
- }
- else
- {
- // manual wizard based on layout
- self.wizard();
- }
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var _this = this;
-
- var items = [];
-
- // we keep a map of all of the properties in our original data object
- // as we render elements out of the schema, we remove from the extraDataProperties map
- // whatever is leftover are the data properties that were NOT rendered because they were not part
- // of the schema
- //
- // this is primarily maintained for debugging purposes, so as to inform the developer of mismatches
- var extraDataProperties = {};
- for (var dataKey in _this.data) {
- extraDataProperties[dataKey] = dataKey;
- }
-
- var properties = _this.data;
- if (_this.schema && _this.schema.properties) {
- properties = _this.schema.properties;
- }
-
- var cf = function()
- {
- // If the schema and the data line up perfectly, then there will be no properties in the data that are
- // not also in the schema, and thus, extraDataProperties will be empty.
- //
- // On the other hand, if there are some properties in data that were not in schema, then they will
- // remain in extraDataProperties and we can inform developers for debugging purposes
- //
- var extraDataKeys = [];
- for (var extraDataKey in extraDataProperties) {
- extraDataKeys.push(extraDataKey);
- }
- if (extraDataKeys.length > 0) {
- Alpaca.logDebug("There were " + extraDataKeys.length + " extra data keys that were not part of the schema " + JSON.stringify(extraDataKeys));
- }
-
- callback(items);
- };
-
- // each property in the object can have a different schema and options so we need to process
- // asynchronously and wait for all to complete
-
- // wrap into waterfall functions
- var propertyFunctions = [];
- for (var propertyId in properties)
- {
- var itemData = null;
- if (_this.data)
- {
- itemData = _this.data[propertyId];
- }
-
- var pf = (function(propertyId, itemData, extraDataProperties)
- {
- return function(callback)
- {
- // only allow this if we have data, otherwise we end up with circular reference
- _this.resolvePropertySchemaOptions(propertyId, function(schema, options, circular) {
-
- // we only allow addition if the resolved schema isn't circularly referenced
- // or the schema is optional
- if (circular)
- {
- return Alpaca.throwErrorWithCallback("Circular reference detected for schema: " + schema, _this.errorCallback);
- }
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for property: " + propertyId);
- }
-
- _this.createItem(propertyId, schema, options, itemData, null, function(addedItemControl) {
-
- items.push(addedItemControl);
-
- // remove from extraDataProperties helper
- delete extraDataProperties[propertyId];
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
- });
- });
- };
-
- })(propertyId, itemData, extraDataProperties);
-
- propertyFunctions.push(pf);
- }
-
- Alpaca.series(propertyFunctions, function(err) {
- cf();
- });
- },
-
- /**
- * Creates an sub-item for this object.
- *
- * The postRenderCallback method is called upon completion.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} postRenderCallback called once the item has been added
- */
- createItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, postRenderCallback)
- {
- var self = this;
-
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(_this, err);
- },
- "notTopLevel":true,
- "render" : function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // add the property Id
- fieldControl.propertyId = propertyId;
- // setup item path
- if (self.path !== "/") {
- fieldControl.path = self.path + "/" + propertyId;
- } else {
- fieldControl.path = self.path + propertyId;
- }
- fieldControl.render(null, function() {
- cb();
- });
- },
- "postRender": function(control) {
-
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- },
-
- /**
- * Determines the schema and options to utilize for sub-objects within this object.
- *
- * @param propertyId
- * @param callback
- */
- resolvePropertySchemaOptions: function(propertyId, callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedPropertySchema, resolvedPropertyOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedPropertyOptions.readonly = true;
- }
-
- callback(resolvedPropertySchema, resolvedPropertyOptions, circular);
- };
-
- var propertySchema = null;
- if (_this.schema && _this.schema.properties && _this.schema.properties[propertyId]) {
- propertySchema = _this.schema.properties[propertyId];
- }
- var propertyOptions = {};
- if (_this.options && _this.options.fields && _this.options.fields[propertyId]) {
- propertyOptions = _this.options.fields[propertyId];
- }
-
- // handle $ref
- if (propertySchema && propertySchema["$ref"])
- {
- var referenceId = propertySchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalPropertySchema = propertySchema;
- var originalPropertyOptions = propertyOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(propertySchema, propertyOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedPropertySchema = {};
- if (originalPropertySchema) {
- Alpaca.mergeObject(resolvedPropertySchema, originalPropertySchema);
- }
- if (propertySchema)
- {
- Alpaca.mergeObject(resolvedPropertySchema, propertySchema);
- }
- // keep original id
- if (originalPropertySchema && originalPropertySchema.id) {
- resolvedPropertySchema.id = originalPropertySchema.id;
- }
- //delete resolvedPropertySchema.id;
-
- var resolvedPropertyOptions = {};
- if (originalPropertyOptions) {
- Alpaca.mergeObject(resolvedPropertyOptions, originalPropertyOptions);
- }
- if (propertyOptions)
- {
- Alpaca.mergeObject(resolvedPropertyOptions, propertyOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedPropertySchema, resolvedPropertyOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(propertySchema, propertyOptions);
- });
- }
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- var f = function(i)
- {
- if (i === model.items.length)
- {
- // done
- callback();
- return;
- }
-
- var item = model.items[i];
-
- var propertyId = item.propertyId;
-
- // HANDLE PROPERTY DEPENDENCIES (IF THE PROPERTY HAS THEM)
-
- // if this property has dependencies, show or hide this added item right away
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- // if this property has dependencies, bind update handlers to dependent fields
- self.bindDependencyFieldUpdateEvent(propertyId);
-
- // if this property has dependencies, trigger those to ensure it is in the right state
- self.refreshDependentFieldStates(propertyId);
-
- f(i+1);
- };
- f(0);
- });
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxProperties();
- valInfo["tooManyProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyProperties"), [this.schema.maxProperties]),
- "status": status
- };
-
- status = this._validateMinProperties();
- valInfo["tooFewProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.minProperties]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyProperties"]["status"] && valInfo["tooFewProperties"]["status"];
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMaxProperties: function()
- {
- if (typeof(this.schema["maxProperties"]) == "undefined")
- {
- return true;
- }
-
- var maxProperties = this.schema["maxProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount <= maxProperties;
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMinProperties: function()
- {
- if (typeof(this.schema["minProperties"]) == "undefined")
- {
- return true;
- }
-
- var minProperties = this.schema["minProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount >= minProperties;
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DEPENDENCIES
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Shows or hides a property's field based on how its dependencies evaluate.
- * If a property doesn't have dependencies, this no-ops.
- *
- * @param propertyId
- */
- showOrHidePropertyBasedOnDependencies: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var valid = this.determineAllDependenciesValid(propertyId);
- if (valid)
- {
- item.show();
- item.onDependentReveal();
- }
- else
- {
- item.hide();
- item.onDependentConceal();
- }
-
- item.getFieldEl().trigger("fieldupdate");
- },
-
- /**
- * Determines whether the dependencies for a property pass.
- *
- * @param propertyId
- */
- determineAllDependenciesValid: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so yes, we pass
- return true;
- }
-
- var valid = true;
- if (Alpaca.isString(itemDependencies))
- {
- valid = self.determineSingleDependencyValid(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- valid = valid && self.determineSingleDependencyValid(propertyId, value);
- });
- }
-
- return valid;
- },
-
- /**
- * Binds field updates to any field dependencies.
- *
- * @param propertyId
- */
- bindDependencyFieldUpdateEvent: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var bindEvent = function(propertyId, dependencyPropertyId)
- {
- // dependencyPropertyId is the identifier for the property that the field "propertyId" is dependent on
-
- var dependentField = Alpaca.resolveField(self, dependencyPropertyId);
- if (dependentField)
- {
- dependentField.getFieldEl().bind("fieldupdate", (function(propertyField, dependencyField, propertyId, dependencyPropertyId) {
-
- return function(event)
- {
- // the property "dependencyPropertyId" changed and affects target property ("propertyId")
-
- // update UI state for target property
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- propertyField.getFieldEl().trigger("fieldupdate");
- };
-
- })(item, dependentField, propertyId, dependencyPropertyId));
-
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- bindEvent(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- bindEvent(propertyId, value);
- });
- }
- },
-
- refreshDependentFieldStates: function(propertyId)
- {
- var self = this;
-
- var propertyField = this.childrenByPropertyId[propertyId];
- if (!propertyField)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = propertyField.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var triggerFieldUpdateForProperty = function(otherPropertyId)
- {
- var dependentField = Alpaca.resolveField(self, otherPropertyId);
- if (dependentField)
- {
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- triggerFieldUpdateForProperty(itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- triggerFieldUpdateForProperty(value);
- });
- }
- },
-
- /**
- * Checks whether a single property's dependency is satisfied or not.
- *
- * In order to be valid, the property's dependency must exist (JSON schema) and optionally must satisfy
- * any dependency options (value matches using an AND). Finally, the dependency field must be showing.
- *
- * @param {Object} propertyId Field property id.
- * @param {Object} dependentOnPropertyId Property id of the dependency field.
- *
- * @returns {Boolean} True if all dependencies have been satisfied and the field needs to be shown,
- * false otherwise.
- */
- determineSingleDependencyValid: function(propertyId, dependentOnPropertyId)
- {
- var self = this;
-
- // checks to see if the referenced "dependent-on" property has a value
- // basic JSON-schema supports this (if it has ANY value, it is considered valid
- // special consideration for boolean false
- var dependentOnField = Alpaca.resolveField(self, dependentOnPropertyId);
- if (!dependentOnField)
- {
- // no dependent-on field found, return false
- return false;
- }
-
- var dependentOnData = dependentOnField.data;
-
- // assume it isn't valid
- var valid = false;
-
- // go one of two directions depending on whether we have conditional dependencies or not
- var conditionalDependencies = this.childrenByPropertyId[propertyId].options.dependencies;
- if (!conditionalDependencies || conditionalDependencies.length === 0)
- {
- //
- // BASIC DEPENENDENCY CHECKING (CORE JSON SCHEMA)
- //
-
- // special case: if the field is a boolean field and we have no conditional dependency checking,
- // then we set valid = false if the field data is a boolean false
- if (dependentOnField.getType() === "boolean" && !this.childrenByPropertyId[propertyId].options.dependencies && !dependentOnData)
- {
- valid = false;
- }
- else
- {
- valid = !Alpaca.isValEmpty(dependentOnField.data);
- }
- }
- else
- {
- //
- // CONDITIONAL DEPENDENCY CHECKING (ALPACA EXTENSION VIA OPTIONS)
- //
-
- // Alpaca extends JSON schema by allowing dependencies to trigger only for specific values on the
- // dependent fields. If options are specified to define this, we walk through and perform an
- // AND operation across any fields
-
- // do some data sanity cleanup
- if (dependentOnField.getType() === "boolean" && !dependentOnData) {
- dependentOnData = false;
- }
-
- var conditionalData = conditionalDependencies[dependentOnPropertyId];
-
- // if the option is a function, then evaluate the function to determine whether to show
- // the function evaluates regardless of whether the schema-based fallback determined we should show
- if (!Alpaca.isEmpty(conditionalData) && Alpaca.isFunction(conditionalData))
- {
- valid = conditionalData.call(this, dependentOnData);
- }
- else
- {
- // assume true
- valid = true;
-
- // the conditional data is an array of values
- if (Alpaca.isArray(conditionalData)) {
-
- // check array value
- //if (conditionalDependencies[dependentOnPropertyId] && $.inArray(dependentOnData, conditionalDependencies[dependentOnPropertyId]) == -1)
- if (Alpaca.anyEquality(dependentOnData, conditionalData))
- {
- valid = false;
- }
- }
- else
- {
- // check object value
- if (!Alpaca.isEmpty(conditionalData) && !Alpaca.anyEquality(conditionalData, dependentOnData))
- {
- valid = false;
- }
- }
- }
- }
-
- //
- // NESTED HIDDENS DEPENDENCY HIDES (ALPACA EXTENSION)
- //
-
- // final check: only set valid if the dependentOnPropertyId is showing
- if (dependentOnField && dependentOnField.isHidden())
- {
- valid = false;
- }
-
- return valid;
- },
-
- /**
- * Gets child index.
- *
- * @param {Object} propertyId Child field property ID.
- */
- getIndex: function(propertyId)
- {
- if (Alpaca.isEmpty(propertyId)) {
- return -1;
- }
- for (var i = 0; i < this.children.length; i++) {
- var pid = this.children[i].propertyId;
- if (pid == propertyId) { // jshint ignore:line
- return i;
- }
- }
- return -1;
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Adds an item to the object.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} callback called once the item has been added
- */
- addItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, callback)
- {
- var self = this;
-
- this.createItem(propertyId, itemSchema, itemOptions, itemData, insertAfterId, function(child) {
-
- var index = null;
- if (insertAfterId && self.childrenById[insertAfterId])
- {
- for (var z = 0; z < self.children.length; z++)
- {
- if (self.children[z].getId() == insertAfterId)
- {
- index = z;
- break;
- }
- }
- }
-
- // register the child
- self.registerChild(child, ((index != null) ? index + 1 : null));
-
- // insert into dom
- if (!index)
- {
- // insert first into container
- $(self.container).append(child.getFieldEl());
- }
- else
- {
- // insert at a specific index
- var existingElement = self.getContainerEl().children("[data-alpaca-container-item-index='" + index + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(child.getFieldEl());
- }
- }
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- //self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState(true, function() {
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
-
- });
- });
- },
-
- /**
- * Removes an item from the object.
- *
- * @param propertyId
- * @param callback
- */
- removeItem: function(propertyId, callback)
- {
- var self = this;
-
- this.children = $.grep(this.children, function(val, index) {
- return (val.getId() != propertyId);
- });
-
- var childField = this.childrenById[propertyId];
-
- delete this.childrenById[propertyId];
- if (childField.propertyId)
- {
- delete this.childrenByPropertyId[childField.propertyId];
- }
-
- childField.destroy();
-
- this.refreshValidationState(true, function() {
-
- // trigger update handler
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // WIZARD
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Wraps the current object into a wizard container and wires up the navigation and buttons so that
- * wizard elements flip nicely.
- */
- wizard: function()
- {
- var self = this;
-
- // config-driven
- var stepDescriptors = this.wizardConfigs.steps;
- if (!stepDescriptors)
- {
- stepDescriptors = [];
- }
- var wizardTitle = this.wizardConfigs.title;
- var wizardDescription = this.wizardConfigs.description;
- var buttonDescriptors = this.wizardConfigs.buttons;
- if (!buttonDescriptors)
- {
- buttonDescriptors = {};
- }
- if (!buttonDescriptors["previous"])
- {
- buttonDescriptors["previous"] = {}
- }
- if (!buttonDescriptors["previous"].title)
- {
- buttonDescriptors["previous"].title = "Previous";
- }
- if (!buttonDescriptors["previous"].align)
- {
- buttonDescriptors["previous"].align = "left";
- }
- if (!buttonDescriptors["previous"].type)
- {
- buttonDescriptors["previous"].type = "button";
- }
- if (!buttonDescriptors["next"])
- {
- buttonDescriptors["next"] = {}
- }
- if (!buttonDescriptors["next"].title)
- {
- buttonDescriptors["next"].title = "Next";
- }
- if (!buttonDescriptors["next"].align)
- {
- buttonDescriptors["next"].align = "right";
- }
- if (!buttonDescriptors["next"].type)
- {
- buttonDescriptors["next"].type = "button";
- }
-
- if (!this.wizardConfigs.hideSubmitButton)
- {
- if (!buttonDescriptors["submit"]) {
- buttonDescriptors["submit"] = {}
- }
- if (!buttonDescriptors["submit"].title) {
- buttonDescriptors["submit"].title = "Submit";
- }
- if (!buttonDescriptors["submit"].align) {
- buttonDescriptors["submit"].align = "right";
- }
- if (!buttonDescriptors["submit"].type) {
- buttonDescriptors["submit"].type = "button";
- }
- }
-
- for (var buttonKey in buttonDescriptors)
- {
- if (!buttonDescriptors[buttonKey].type)
- {
- buttonDescriptors[buttonKey].type = "button";
- }
- }
- var showSteps = this.wizardConfigs.showSteps;
- if (typeof(showSteps) == "undefined")
- {
- showSteps = true;
- }
- var showProgressBar = this.wizardConfigs.showProgressBar;
- var performValidation = this.wizardConfigs.validation;
- if (typeof(performValidation) == "undefined")
- {
- performValidation = true;
- }
-
- // DOM-driven configuration
- var wizardTitle = $(this.field).attr("data-alpaca-wizard-title");
- var wizardDescription = $(this.field).attr("data-alpaca-wizard-description");
- var _wizardValidation = $(this.field).attr("data-alpaca-wizard-validation");
- if (typeof(_wizardValidation) != "undefined")
- {
- performValidation = _wizardValidation ? true : false;
- }
- var _wizardShowSteps = $(this.field).attr("data-alpaca-wizard-show-steps");
- if (typeof(_wizardShowSteps) != "undefined")
- {
- showSteps = _wizardShowSteps ? true : false;
- }
- var _wizardShowProgressBar = $(this.field).attr("data-alpaca-wizard-show-progress-bar");
- if (typeof(_wizardShowProgressBar) != "undefined")
- {
- showProgressBar = _wizardShowProgressBar ? true : false;
- }
-
- // find all of the steps
- var stepEls = $(this.field).find("[data-alpaca-wizard-role='step']");
-
- // DOM-driven configuration of step descriptors
- if (stepDescriptors.length == 0)
- {
- stepEls.each(function(i) {
-
- var stepDescriptor = {};
-
- var stepTitle = $(this).attr("data-alpaca-wizard-step-title");
- if (typeof(stepTitle) != "undefined")
- {
- stepDescriptor.title = stepTitle;
- }
- if (!stepDescriptor.title)
- {
- stepDescriptor.title = "Step " + i;
- }
-
- var stepDescription = $(this).attr("data-alpaca-wizard-step-description");
- if (typeof(stepDescription) != "undefined")
- {
- stepDescriptor.description = stepDescription;
- }
- if (!stepDescriptor.description)
- {
- stepDescriptor.description = "Step " + i;
- }
-
- stepDescriptors.push(stepDescriptor);
- });
- }
-
- // assume something for progress bar if not specified
- if (typeof(showProgressBar) == "undefined")
- {
- if (stepDescriptors.length > 1)
- {
- showProgressBar = true;
- }
- }
-
-
- // model for use in rendering the wizard
- var model = {};
- model.wizardTitle = wizardTitle;
- model.wizardDescription = wizardDescription;
- model.showSteps = showSteps;
- model.performValidation = performValidation;
- model.steps = stepDescriptors;
- model.buttons = buttonDescriptors;
- model.schema = self.schema;
- model.options = self.options;
- model.data = self.data;
- model.showProgressBar = showProgressBar;
- model.markAllStepsVisited = this.wizardConfigs.markAllStepsVisited;
- model.view = self.view;
-
- // render the actual wizard
- var wizardTemplateDescriptor = self.view.getTemplateDescriptor("wizard", self);
- if (wizardTemplateDescriptor)
- {
- var wizardEl = Alpaca.tmpl(wizardTemplateDescriptor, model);
-
- $(self.field).append(wizardEl);
-
- var wizardNav = $(wizardEl).find(".alpaca-wizard-nav");
- var wizardSteps = $(wizardEl).find(".alpaca-wizard-steps");
- var wizardButtons = $(wizardEl).find(".alpaca-wizard-buttons");
- var wizardProgressBar = $(wizardEl).find(".alpaca-wizard-progress-bar");
-
- // move steps into place
- $(wizardSteps).append(stepEls);
-
- (function(wizardNav, wizardSteps, wizardButtons, model) {
-
- var currentIndex = 0;
-
- var previousButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='previous']");
- var nextButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='next']");
- var submitButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='submit']");
-
- // snap into place a little controller to work the buttons
- // assume the first step
- var refreshSteps = function()
- {
- // NAV
- if (model.showSteps)
- {
- if (!model.visits)
- {
- model.visits = {};
- }
-
- // optionally mark all steps as visited
- if (model.markAllStepsVisited)
- {
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- for (var g = 0; g < stepElements.length; g++)
- {
- model.visits[g] = true;
- }
- }
-
- // mark current step as visited
- model.visits[currentIndex] = true;
-
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- $(stepElements).removeClass("disabled");
- $(stepElements).removeClass("completed");
- $(stepElements).removeClass("active");
- $(stepElements).removeClass("visited");
- for (var g = 0; g < stepElements.length; g++)
- {
- if (g < currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("completed");
- }
- else if (g === currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("active");
- }
- else
- {
- if (model.visits && model.visits[g])
- {
- // do not mark disabled for this case
- }
- else
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("disabled");
- }
-
- }
-
- if (model.visits && model.visits[g])
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("visited");
- }
- }
- }
-
- // PROGRESS BAR
- if (model.showProgressBar)
- {
- var valueNow = currentIndex + 1;
- var valueMax = model.steps.length + 1;
- var width = parseInt(((valueNow / valueMax) * 100), 10) + "%";
-
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuemax", valueMax);
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuenow", valueNow);
- $(wizardProgressBar).find(".progress-bar").css("width", width);
- }
-
-
- // BUTTONS
-
- // hide everything
- previousButtonEl.hide();
- nextButtonEl.hide();
- submitButtonEl.hide();
-
- // simple case
- if (model.steps.length == 1)
- {
- submitButtonEl.show();
- }
- else if (model.steps.length > 1)
- {
- if (currentIndex > 0)
- {
- previousButtonEl.show();
- }
-
- nextButtonEl.show();
-
- if (currentIndex == 0)
- {
- nextButtonEl.show();
- }
- else if (currentIndex == model.steps.length - 1)
- {
- nextButtonEl.hide();
- submitButtonEl.show();
- }
- }
-
- // hide all steps
- $(wizardSteps).find("[data-alpaca-wizard-role='step']").hide();
- $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]).show();
-
- };
-
- var assertValidation = function(buttonId, callback)
- {
- if (!model.performValidation)
- {
- callback(true);
- return;
- }
-
- // collect all of the fields on the current step
- var fields = [];
-
- var currentStepEl = $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]);
- $(currentStepEl).find(".alpaca-field").each(function() {
- var fieldId = $(this).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var field = self.childrenById[fieldId];
- if (field)
- {
- fields.push(field);
- }
- }
- });
-
- // wrap into validation functions
- var fns = [];
- for (var i = 0; i < fields.length; i++)
- {
- fns.push(function(field) {
- return function(cb)
- {
- field.refreshValidationState(true, function() {
- cb();
- });
- }
- }(fields[i]));
- }
-
- // run all validations
- Alpaca.series(fns, function() {
-
- var valid = true;
- for (var i = 0; i < fields.length; i++)
- {
- valid = valid && fields[i].isValid(true);
- }
-
- // custom validation function?
- var b = model.buttons[buttonId];
- if (b && b.validate)
- {
- b.validate.call(self, function(_valid) {
- valid = valid && _valid;
- callback(valid);
- });
- }
- else
- {
- callback(valid);
- }
- });
- };
-
- $(previousButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex >= 1)
- {
- //assertValidation("previous", function(valid) {
-
- //if (valid)
- //{
- var b = model.buttons["previous"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex--;
-
- refreshSteps();
- //}
- //});
- }
- });
-
- $(nextButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex + 1 <= model.steps.length - 1)
- {
- assertValidation("next", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["next"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex++;
-
- refreshSteps();
- }
- });
- }
- });
-
- $(submitButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex === model.steps.length - 1)
- {
- assertValidation("submit", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["submit"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- else
- {
- // are we in a form?
- if (self.form)
- {
- self.form.submit();
- }
- }
- }
- }
- });
- }
- });
-
- // all custom buttons
- $(wizardButtons).find("[data-alpaca-wizard-button-key]").each(function() {
- var key = $(this).attr("data-alpaca-wizard-button-key");
- if (key != "submit" && key != "next" && key != "previous") { // standard buttons have different behavior
- var b = model.buttons[key];
- if (b && b.click) {
- $(this).click(function (b) {
- return function (e) {
- b.click.call(self, e);
- };
- }(b));
- }
- }
- });
-
- $(wizardNav).find("[data-alpaca-wizard-step-index]").click(function(e) {
- e.preventDefault();
-
- var navIndex = $(this).attr("data-alpaca-wizard-step-index");
- if (navIndex)
- {
- navIndex = parseInt(navIndex, 10);
-
- if (navIndex == currentIndex || (model.visits && model.visits[navIndex]))
- {
- // if we're going backwards, then we do not run validation
- if (navIndex < currentIndex)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- else if (navIndex > currentIndex)
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- });
- }
- else
- {
- // current item should not be clickable
- }
- }
- }
- });
-
- self.on("moveToStep", function(event) {
-
- var index = event.index;
- var skipValidation = event.skipValidation;
-
- if ((typeof(index) !== "undefined") && index <= model.steps.length - 1)
- {
- if (skipValidation)
- {
- currentIndex = index;
- refreshSteps();
- }
- else
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = index;
-
- refreshSteps();
- }
- });
- }
- }
- });
-
- self.on("advanceOrSubmit", function(event) {
-
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- if (currentIndex === model.steps.length - 1)
- {
- $(submitButtonEl).click();
- }
- else
- {
- $(nextButtonEl).click();
- }
- }
- });
- });
-
-
- refreshSteps();
-
- }(wizardNav, wizardSteps, wizardButtons, model));
- }
- },
-
- /**
- * Renders a configuration-based wizard without a layout template.
- */
- autoWizard: function()
- {
- var stepBindings = this.wizardConfigs.bindings;
- if (!stepBindings)
- {
- stepBindings = {};
- }
-
- for (var propertyId in this.childrenByPropertyId)
- {
- if (!stepBindings.hasOwnProperty(propertyId))
- {
- stepBindings[propertyId] = 1;
- }
- }
-
- // should we create steps?
- var createSteps = true;
- if ($(this.field).find("[data-alpaca-wizard-role='step']").length > 0)
- {
- // already there
- createSteps = false;
- }
-
- var step = 1;
- var col = [];
- do
- {
- // collect fields in this step
- col = [];
- for (var propertyId in stepBindings)
- {
- if (stepBindings[propertyId] == step)
- {
- if (this.childrenByPropertyId && this.childrenByPropertyId[propertyId])
- {
- col.push(this.childrenByPropertyId[propertyId].field);
- }
- }
- }
-
- if (col.length > 0)
- {
- var stepEl = null;
- if (createSteps)
- {
- stepEl = $('');
- $(this.field).append(stepEl);
- }
- else
- {
- stepEl = $($(this.field).find("[data-alpaca-wizard-role='step']")[step-1]);
- }
-
- // move elements in
- for (var i = 0; i < col.length; i++)
- {
- $(stepEl).append(col[i]);
- }
-
- step++;
- }
- }
- while (col.length > 0);
-
- // now run the normal wizard
- this.wizard();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "object";
- },
-
- /**
- * Moves a field.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to which the child should be moved
- * @param [Boolean] animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + sourceIndex + "']");
- var targetContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + targetIndex + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find("[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find("[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- if (animate)
- {
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, 500, function() {
- onComplete();
- });
- }
- else
- {
- onComplete();
- }
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Object Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Object field for containing other fields";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "properties": {
- "title": "Properties",
- "description": "List of child properties.",
- "type": "object"
- },
- "maxProperties": {
- "type": "number",
- "title": "Maximum Number Properties",
- "description": "The maximum number of properties that this object is allowed to have"
- },
- "minProperties": {
- "type": "number",
- "title": "Minimum Number of Properties",
- "description": "The minimum number of properties that this object is required to have"
- }
- }
- };
-
- var fieldsProperties = properties.properties.properties;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfSchema();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = Alpaca.merge(this.base(), {
- "properties": {
- }
- });
-
- var properties = {
- "properties": {
- "fields": {
- "title": "Field Options",
- "description": "List of options for child fields.",
- "type": "object"
- }
- }
- };
-
- var fieldsProperties = properties.properties.fields;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfOptions();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(schemaOfOptions, properties);
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "tooManyProperties": "The maximum number of properties ({0}) has been exceeded.",
- "tooFewProperties": "There are not enough properties ({0} are required)"
- });
-
- Alpaca.registerFieldClass("object", Alpaca.Fields.ObjectField);
- Alpaca.registerDefaultSchemaFieldMapping("object", "object");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AnyField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.AnyField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "any";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.control.disabled = true;
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.control.disabled = false;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- this.control.focus();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "any";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Any Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Any field.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("any", Alpaca.Fields.AnyField);
- Alpaca.registerDefaultSchemaFieldMapping("any", "any");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.HiddenField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ControlField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "hidden";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value)) {
- this.getControlEl().val("");
- } else {
- this.getControlEl().val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Hidden";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Field for a hidden HTML input";
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("hidden", Alpaca.Fields.HiddenField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AddressField = Alpaca.Fields.ObjectField.extend(
- /**
- * @lends Alpaca.Fields.AddressField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.ObjectField#getFieldType
- */
- getFieldType: function() {
- return "address";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.data === undefined) {
- this.data = {
- street: ['', '']
- };
- }
-
- this.schema = {
- "title": "Home Address",
- "type": "object",
- "properties": {
- "street": {
- "title": "Street",
- "type": "array",
- "items": {
- "type": "string",
- "maxLength": 30,
- "minItems": 0,
- "maxItems": 3
- }
- },
- "city": {
- "title": "City",
- "type": "string"
- },
- "state": {
- "title": "State",
- "type": "string",
- "enum": ["AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY"]
- },
- "zip": {
- "title": "Zip Code",
- "type": "string",
- "pattern": /^(\d{5}(-\d{4})?)?$/
- }
- }
- };
- Alpaca.merge(this.options, {
- "fields": {
- "zip": {
- "maskString": "99999",
- "size": 5
- },
- "state": {
- "optionLabels": ["ALABAMA", "ALASKA", "AMERICANSAMOA", "ARIZONA", "ARKANSAS", "CALIFORNIA", "COLORADO", "CONNECTICUT", "DELAWARE", "DISTRICTOFCOLUMBIA", "FEDERATEDSTATESOFMICRONESIA", "FLORIDA", "GEORGIA", "GUAM", "HAWAII", "IDAHO", "ILLINOIS", "INDIANA", "IOWA", "KANSAS", "KENTUCKY", "LOUISIANA", "MAINE", "MARSHALLISLANDS", "MARYLAND", "MASSACHUSETTS", "MICHIGAN", "MINNESOTA", "MISSISSIPPI", "MISSOURI", "MONTANA", "NEBRASKA", "NEVADA", "NEWHAMPSHIRE", "NEWJERSEY", "NEWMEXICO", "NEWYORK", "NORTHCAROLINA", "NORTHDAKOTA", "NORTHERNMARIANAISLANDS", "OHIO", "OKLAHOMA", "OREGON", "PALAU", "PENNSYLVANIA", "PUERTORICO", "RHODEISLAND", "SOUTHCAROLINA", "SOUTHDAKOTA", "TENNESSEE", "TEXAS", "UTAH", "VERMONT", "VIRGINISLANDS", "VIRGINIA", "WASHINGTON", "WESTVIRGINIA", "WISCONSIN", "WYOMING"]
- }
- }
- });
-
- if (Alpaca.isEmpty(this.options.addressValidation))
- {
- this.options.addressValidation = true;
- }
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return false;
- },
-
- /**
- * Returns address in a single line string.
- *
- * @returns {String} Address as a single line string.
- */
- getAddress: function()
- {
- var value = this.getValue();
- if (this.view.type === "view")
- {
- value = this.data;
- }
- var address = "";
- if (value)
- {
- if (value.street)
- {
- $.each(value.street, function(index, value) {
- address += value + " ";
- });
- }
- if (value.city)
- {
- address += value.city + " ";
- }
- if (value.state)
- {
- address += value.state + " ";
- }
- if (value.zip)
- {
- address += value.zip;
- }
- }
-
- return address;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
- var container = self.getContainerEl();
-
- // apply additional css
- $(container).addClass("alpaca-addressfield");
-
- if (self.options.addressValidation && !self.isDisplayOnly())
- {
- $('').appendTo(container);
- var mapButton = $(' ').appendTo(container);
- if (mapButton.button)
- {
- mapButton.button({
- text: true
- });
- }
- mapButton.click(function() {
-
- if (google && google.maps)
- {
- var geocoder = new google.maps.Geocoder();
- var address = self.getAddress();
- if (geocoder)
- {
- geocoder.geocode({
- 'address': address
- }, function(results, status)
- {
- if (status === google.maps.GeocoderStatus.OK)
- {
- var mapCanvasId = self.getId() + "-map-canvas";
- if ($('#' + mapCanvasId).length === 0)
- {
- $("").appendTo(self.getFieldEl());
- }
-
- var map = new google.maps.Map(document.getElementById(self.getId() + "-map-canvas"), {
- "zoom": 10,
- "center": results[0].geometry.location,
- "mapTypeId": google.maps.MapTypeId.ROADMAP
- });
-
- var marker = new google.maps.Marker({
- map: map,
- position: results[0].geometry.location
- });
-
- }
- else
- {
- self.displayMessage("Geocoding failed: " + status);
- }
- });
- }
-
- }
- else
- {
- self.displayMessage("Google Map API is not installed.");
- }
- }).wrap('');
-
- if (self.options.showMapOnLoad)
- {
- mapButton.click();
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getType
- */
- getType: function() {
- return "any";
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.ObjectField#getTitle
- */
- getTitle: function() {
- return "Address";
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getDescription
- */
- getDescription: function() {
- return "Standard US Address with Street, City, State and Zip. Also comes with support for Google map.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "validateAddress": {
- "title": "Address Validation",
- "description": "Enable address validation if true",
- "type": "boolean",
- "default": true
- },
- "showMapOnLoad": {
- "title": "Whether to show the map when first loaded",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "validateAddress": {
- "helper": "Address validation if checked",
- "rightLabel": "Enable Google Map for address validation?",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("address", Alpaca.Fields.AddressField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CKEditorField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.CKEditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "ckeditor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- if (!this.data)
- {
- this.data = "";
- }
-
- this.base();
-
- if (typeof(this.options.ckeditor) == "undefined")
- {
- this.options.ckeditor = {};
- }
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // see if we can render CK Editor
- if (!self.isDisplayOnly() && self.control && typeof(CKEDITOR) !== "undefined")
- {
- // use a timeout because CKEditor has some odd timing dependencies
- setTimeout(function() {
-
- self.editor = CKEDITOR.replace($(self.control)[0], self.options.ckeditor);
-
- }, 250);
- }
-
- // if the ckeditor's dom element gets destroyed, make sure we clean up the editor instance
- $(self.control).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.removeAllListeners();
- self.editor.destroy(false);
- self.editor = null;
- }
-
- });
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the plugin instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- }
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- ,
- getTitle: function() {
- return "CK Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Provides an instance of a CK Editor control for use in editing HTML.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "ckeditor": {
- "title": "CK Editor options",
- "description": "Use this entry to provide configuration options to the underlying CKEditor plugin.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "ckeditor": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("ckeditor", Alpaca.Fields.CKEditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ColorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ColorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "color";
- this.inputType = "color";
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "color";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Color Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A color picker for selecting hexadecimal color values";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("color", Alpaca.Fields.ColorField);
- Alpaca.registerDefaultSchemaFieldMapping("color", "color");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CountryField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.CountryField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "country";
- },
-
- /**
- * @see Alpaca.Fields.Field#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize))
- {
- this.options.capitalize = false;
- }
-
- this.schema["enum"] = [];
- this.options.optionLabels = [];
-
- var countriesMap = this.view.getMessage("countries");
- if (countriesMap)
- {
- for (var countryKey in countriesMap)
- {
- this.schema["enum"].push(countryKey);
-
- var label = countriesMap[countryKey];
- if (this.options.capitalize)
- {
- label = label.toUpperCase();
- }
-
- this.options.optionLabels.push(label);
- }
- }
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Country Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of countries keyed by their ISO3 code. The names of the countries are read from the I18N bundle for the current locale.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "capitalize": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("country", Alpaca.Fields.CountryField);
- Alpaca.registerDefaultFormatFieldMapping("country", "country");
-
-})(jQuery);
-
-(function($) {
-
- var round = (function() {
- var strategies = {
- up: Math.ceil,
- down: function(input) { return ~~input; },
- nearest: Math.round
- };
- return function(strategy) {
- return strategies[strategy];
- };
- })();
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CurrencyField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.CurrencyField.prototype
- */
- {
- /**
- * @constructs
- * @augments Alpaca.Fields.TextField
- *
- * @class Currency Control
- *
- * @param {Object} container Field container.
- * @param {Any} data Field data.
- * @param {Object} options Field options.
- * @param {Object} schema Field schema.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(container, data, options, schema, view, connector, errorCallback) {
- options = options || {};
-
- var pfOptionsSchema = this.getSchemaOfPriceFormatOptions().properties;
- for (var i in pfOptionsSchema) {
- var option = pfOptionsSchema[i];
- if (!(i in options)) {
- options[i] = option["default"] || undefined;
- }
- }
-
- if (typeof(data) !== "undefined")
- {
- data = "" + parseFloat(data).toFixed(options.centsLimit);
- }
-
- this.base(container, data, options, schema, view, connector, errorCallback);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "currency";
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- var field = this.getControlEl();
-
- this.base(model, function() {
-
- $(field).priceFormat(self.options);
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function() {
-
- var field = this.getControlEl();
-
- var val = $(field).is('input') ? field.val() : field.hmtl();
- if (this.options.unmask || this.options.round !== "none") {
- var unmasked = function() {
- var result = '';
- for (var i in val) {
- var cur = val[i];
- if (!isNaN(cur)) {
- result += cur;
- } else if (cur === this.options.centsSeparator) {
- result += '.';
- }
- }
- return parseFloat(result);
- }.bind(this)();
- if (this.options.round !== "none") {
- unmasked = round(this.options.round)(unmasked);
- if (!this.options.unmask) {
- var result = [];
- var unmaskedString = "" + unmasked;
- for (var i = 0, u = 0; i < val.length; i++) {
- if (!isNaN(val[i])) {
- result.push(unmaskedString[u++] || 0);
- } else {
- result.push(val[i]);
- }
- }
- return result.join('');
- }
- }
- return unmasked;
- } else {
- return val;
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Currency Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides an automatically formatted and configurable input for entering currency amounts.";
- },
-
- getSchemaOfPriceFormatOptions: function() {
- return {
- "properties": {
- "allowNegative": {
- "title": "Allow Negative",
- "description": "Determines if negative numbers are allowed.",
- "type": "boolean",
- "default": false
- },
- "centsLimit": {
- "title": "Cents Limit",
- "description": "The limit of fractional digits.",
- "type": "number",
- "default": 2,
- "minimum": 0
- },
- "centsSeparator": {
- "title": "Cents Separator",
- "description": "The separator between whole and fractional amounts.",
- "type": "text",
- "default": "."
- },
- "clearPrefix": {
- "title": "Clear Prefix",
- "description": "Determines if the prefix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "clearSuffix": {
- "title": "Clear Suffix",
- "description": "Determines if the suffix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "insertPlusSign": {
- "title": "Plus Sign",
- "description": "Determines if a plus sign should be inserted for positive values.",
- "type": "boolean",
- "default": false
- },
- "limit": {
- "title": "Limit",
- "description": "A limit of the length of the field.",
- "type": "number",
- "default": undefined,
- "minimum": 0
- },
- "prefix": {
- "title": "Prefix",
- "description": "The prefix if any for the field.",
- "type": "text",
- "default": "$"
- },
- "round": {
- "title": "Round",
- "description": "Determines if the field is rounded. (Rounding is done when getValue is called and is not reflected in the UI)",
- "type": "string",
- "enum": [ "up", "down", "nearest", "none" ],
- "default": "none"
- },
- "suffix": {
- "title": "Suffix",
- "description": "The suffix if any for the field.",
- "type": "text",
- "default": ""
- },
- "thousandsSeparator": {
- "title": "Thousands Separator",
- "description": "The separator between thousands.",
- "type": "string",
- "default": ","
- },
- "unmask": {
- "title": "Unmask",
- "description": "If true then the resulting value for this field will be unmasked. That is, the resulting value will be a float instead of a string (with the prefix, suffix, etc. removed).",
- "type": "boolean",
- "default": true
- }
- }
- };
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), this.getSchemaOfPriceFormatOptions());
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "allowNegative": {
- "type": "checkbox"
- },
- "centsLimit": {
- "type": "number"
- },
- "centsSeparator": {
- "type": "text"
- },
- "clearPrefix": {
- "type": "checkbox"
- },
- "clearSuffix": {
- "type": "checkbox"
- },
- "insertPlusSign": {
- "type": "checkbox"
- },
- "limit": {
- "type": "number"
- },
- "prefix": {
- "type": "text"
- },
- "round": {
- "type": "select"
- },
- "suffix": {
- "type": "text"
- },
- "thousandsSeparator": {
- "type": "string"
- },
- "unmask": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("currency", Alpaca.Fields.CurrencyField);
-
-})(jQuery);
-
-(function($) {
-
- // NOTE: this requires bootstrap-datetimepicker.js
- // NOTE: this requires moment.js
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DateField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.DateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "date";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY";
- },
-
- getDefaultExtraFormats: function() {
- return [];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "date";
- //this.inputType = "date";
-
- this.base();
-
- if (!self.options.picker)
- {
- self.options.picker = {};
- }
-
- if (typeof(self.options.picker.useCurrent) === "undefined") {
- self.options.picker.useCurrent = false;
- }
-
- // date format
-
- if (self.options.picker.format) {
- self.options.dateFormat = self.options.picker.format;
- }
- if (!self.options.dateFormat) {
- self.options.dateFormat = self.getDefaultFormat();
- }
- if (!self.options.picker.format) {
- self.options.picker.format = self.options.dateFormat;
- }
-
- // extra formats
- if (!self.options.picker.extraFormats) {
- var extraFormats = self.getDefaultExtraFormats();
- if (extraFormats) {
- self.options.picker.extraFormats = extraFormats;
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#afterRenderControl
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- if (self.view.type !== "display")
- {
- if ($.fn.datetimepicker)
- {
- self.getControlEl().datetimepicker(self.options.picker);
-
- self.picker = self.getControlEl().data("DateTimePicker");
- if (self.picker && self.options.dateFormat)
- {
- self.picker.format(self.options.dateFormat);
- }
- if (self.picker)
- {
- self.options.dateFormat = self.picker.format();
- }
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- getDate: function()
- {
- var self = this;
-
- var date = null;
- try
- {
- if (self.picker)
- {
- date = (self.picker.date() ? self.picker.date()._d: null);
- }
- else
- {
- date = new Date(this.getValue());
- }
- }
- catch (e)
- {
- console.error(e);
- }
-
- return date;
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- date: function()
- {
- return this.getDate();
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- this.refreshValidationState();
- },
-
- isAutoFocusable: function()
- {
- return false;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateDateFormat();
- valInfo["invalidDate"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidDate"), [this.options.dateFormat]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidDate"]["status"];
- },
-
- /**
- * Validates date format.
- *
- * @returns {Boolean} True if it is a valid date, false otherwise.
- */
- _validateDateFormat: function()
- {
- var self = this;
-
- var isValid = true;
-
- if (self.options.dateFormat)
- {
- var value = self.getValue();
- if (value || self.isRequired())
- {
- // collect all formats
- var dateFormats = [];
- dateFormats.push(self.options.dateFormat);
- if (self.options.picker && self.options.picker.extraFormats)
- {
- for (var i = 0; i < self.options.picker.extraFormats.length; i++)
- {
- dateFormats.push(self.options.picker.extraFormats[i]);
- }
- }
-
- for (var i = 0; i < dateFormats.length; i++)
- {
- isValid = isValid || moment(value, self.options.dateFormat, true).isValid();
- }
- }
- }
-
- return isValid;
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- this.base(value);
-
- if (this.picker)
- {
- if (moment(value, self.options.dateFormat, true).isValid())
- {
- this.picker.date(value);
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- return this.base();
- },
-
- destroy: function()
- {
- this.base();
-
- this.picker = null;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Date Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Date Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"date",
- "enum" : ["date"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "dateFormat": {
- "title": "Date Format",
- "description": "Date format (using moment.js format)",
- "type": "string"
- },
- "picker": {
- "title": "DatetimePicker options",
- "description": "Options that are supported by the Bootstrap DateTime Picker.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "dateFormat": {
- "type": "text"
- },
- "picker": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidDate": "Invalid date for format {0}"
- });
- Alpaca.registerFieldClass("date", Alpaca.Fields.DateField);
- Alpaca.registerDefaultFormatFieldMapping("date", "date");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DatetimeField = Alpaca.Fields.DateField.extend(
- /**
- * @lends Alpaca.Fields.DatetimeField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "datetime";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY HH:mm:ss";
- },
-
- getDefaultExtraFormats: function() {
- return [
- "MM/DD/YYYY hh:mm:ss a",
- "MM/DD/YYYY HH:mm",
- "MM/DD/YYYY"
- ];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "datetime";
- //this.inputType = "datetime";
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Datetime Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Datetime Field based on Bootstrap DateTime Picker.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("datetime", Alpaca.Fields.DatetimeField);
-
- // "datetime" is legacy (pre v4 schema)
- Alpaca.registerDefaultFormatFieldMapping("datetime", "datetime");
-
- // official v4 uses date-time
- Alpaca.registerDefaultFormatFieldMapping("date-time", "datetime");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EditorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "editor";
- },
-
- setup: function()
- {
- var self = this;
-
- this.base();
-
- if (!self.options.aceTheme)
- {
- self.options.aceTheme = "ace/theme/chrome";
- }
-
- if (!self.options.aceMode)
- {
- self.options.aceMode = "ace/mode/json";
- }
-
- if (typeof(self.options.beautify) == "undefined")
- {
- self.options.beautify = true;
- }
-
- if (self.options.beautify && this.data)
- {
- if (self.options.aceMode === "ace/mode/json")
- {
- if (Alpaca.isObject(this.data))
- {
- // convert to string to format it
- this.data = JSON.stringify(this.data, null, " ");
- }
- else if (Alpaca.isString(this.data))
- {
- // convert to object and then back to string to format it
- this.data = JSON.stringify(JSON.parse(this.data), null, " ");
- }
- }
-
- if (self.options.aceMode === "ace/mode/html")
- {
- if (typeof(html_beautify) !== "undefined")
- {
- this.data = html_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/css")
- {
- if (typeof(css_beautify) !== "undefined")
- {
- this.data = css_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/javascript")
- {
- if (typeof(js_beautify) !== "undefined")
- {
- this.data = js_beautify(this.data);
- }
- }
- }
-
- if (self.options.aceMode === "ace/mode/json")
- {
- if (!this.data || this.data === "{}")
- {
- this.data = "{\n\t\n}";
- }
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // ACE HEIGHT
- var aceHeight = self.options.aceHeight;
- if (aceHeight)
- {
- $(self.control).css("height", aceHeight);
- }
-
- // ACE WIDTH
- var aceWidth = self.options.aceWidth;
- if (!aceWidth) {
- aceWidth = "100%";
- }
- $(self.control).css("width", aceWidth);
- }
-
- // locate where we will insert the editor
- var el = $(self.control)[0];
-
- // ace must be included ahead of time
- if (!ace && window.ace) {
- ace = window.ace;
- }
-
- if (!ace)
- {
- Alpaca.logError("Editor Field is missing the 'ace' Cloud 9 Editor");
- }
- else
- {
- self.editor = ace.edit(el);
- self.editor.setOptions({
- maxLines: Infinity
- });
-
- self.editor.getSession().setUseWrapMode(true);
-
- // theme
- var aceTheme = self.options.aceTheme;
- self.editor.setTheme(aceTheme);
-
- // mode
- var aceMode = self.options.aceMode;
- self.editor.getSession().setMode(aceMode);
-
- self.editor.renderer.setHScrollBarAlwaysVisible(false);
- //this.editor.renderer.setVScrollBarAlwaysVisible(false); // not implemented
- self.editor.setShowPrintMargin(false);
-
- // set data onto editor
- self.editor.setValue(self.data);
- self.editor.clearSelection();
-
- // clear undo session
- self.editor.getSession().getUndoManager().reset();
-
- // FIT-CONTENT the height of the editor to the contents contained within
- if (self.options.aceFitContentHeight)
- {
- var heightUpdateFunction = function() {
-
- var first = false;
- if (self.editor.renderer.lineHeight === 0)
- {
- first = true;
- self.editor.renderer.lineHeight = 16;
- }
-
- // http://stackoverflow.com/questions/11584061/
- var newHeight = self.editor.getSession().getScreenLength() * self.editor.renderer.lineHeight + self.editor.renderer.scrollBar.getWidth();
-
- $(self.control).height(newHeight.toString() + "px");
-
- // This call is required for the editor to fix all of
- // its inner structure for adapting to a change in size
- self.editor.resize();
-
- if (first)
- {
- window.setTimeout(function() {
- self.editor.clearSelection();
- }, 100);
- }
- };
-
- // Set initial size to match initial content
- heightUpdateFunction();
-
- // Whenever a change happens inside the ACE editor, update
- // the size again
- self.editor.getSession().on('change', heightUpdateFunction);
- }
-
- // READONLY
- if (self.schema.readonly)
- {
- self.editor.setReadOnly(true);
- }
-
- // if the editor's dom element gets destroyed, make sure we clean up the editor instance
- // normally, we expect Alpaca fields to be destroyed by the destroy() method but they may also be
- // cleaned-up via the DOM, thus we check here.
- $(el).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.destroy();
- self.editor = null;
- }
-
- });
- }
-
- callback();
- });
-
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the editor instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- },
-
- /**
- * @return the ACE editor instance
- */
- getEditor: function()
- {
- return this.editor;
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var wordCountStatus = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": wordCountStatus ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": wordCountStatus
- };
-
- var editorAnnotationsStatus = this._validateEditorAnnotations();
- valInfo["editorAnnotationsExist"] = {
- "message": editorAnnotationsStatus ? "" : this.view.getMessage("editorAnnotationsExist"),
- "status": editorAnnotationsStatus
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"] && valInfo["editorAnnotationsExist"]["status"];
- },
-
- _validateEditorAnnotations: function()
- {
- if (this.editor)
- {
- var annotations = this.editor.getSession().getAnnotations();
- if (annotations && annotations.length > 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.editor.getValue();
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Force editor to resize to ensure it gets drawn correctly.
- * @override
- */
- onDependentReveal: function()
- {
- if (this.editor)
- {
- this.editor.resize();
- }
- },
-
- /**
- *@see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- if (this.editor)
- {
- if (self.schema.type == "object" && Alpaca.isObject(value))
- {
- // format
- value = JSON.stringify(value, null, " ");
- }
-
- this.editor.setValue(value);
- self.editor.clearSelection();
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var value = null;
-
- if (this.editor)
- {
- value = this.editor.getValue();
- }
-
- // if expected type back is "object", we do the conversion
- if (this.schema.type == "object")
- {
- if (!value)
- {
- value = {};
- }
- else
- {
- value = JSON.parse(value);
- }
- }
-
- return value;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Editor";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "aceTheme": {
- "title": "ACE Editor Theme",
- "description": "Specifies the theme to set onto the editor instance",
- "type": "string",
- "default": "ace/theme/twilight"
- },
- "aceMode": {
- "title": "ACE Editor Mode",
- "description": "Specifies the mode to set onto the editor instance",
- "type": "string",
- "default": "ace/mode/javascript"
- },
- "aceWidth": {
- "title": "ACE Editor Height",
- "description": "Specifies the width of the wrapping div around the editor",
- "type": "string",
- "default": "100%"
- },
- "aceHeight": {
- "title": "ACE Editor Height",
- "description": "Specifies the height of the wrapping div around the editor",
- "type": "string",
- "default": "300px"
- },
- "aceFitContentHeight": {
- "title": "ACE Fit Content Height",
- "description": "Configures the ACE Editor to auto-fit its height to the contents of the editor",
- "type": "boolean",
- "default": false
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "aceTheme": {
- "type": "text"
- },
- "aceMode": {
- "type": "text"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded.",
- "editorAnnotationsExist": "The editor has errors in it that must be corrected"
- });
-
- Alpaca.registerFieldClass("editor", Alpaca.Fields.EditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EmailField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EmailField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "email";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "email";
- this.inputType = "email";
-
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.email;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidEmail");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Email Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Email Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.email;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"email",
- "enum":["email"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidEmail": "Invalid Email address e.g. info@cloudcms.com"
- });
- Alpaca.registerFieldClass("email", Alpaca.Fields.EmailField);
- Alpaca.registerDefaultFormatFieldMapping("email", "email");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.GridField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.GridField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "grid";
- },
-
- setup: function()
- {
- this.base();
-
- if (typeof(this.options.grid) == "undefined")
- {
- this.options.grid = {};
- }
- },
-
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // convert the data array into the grid's expected format
- var gridData = [];
-
- // add in headers
- var headers = [];
- for (var key in self.options.fields)
- {
- var fieldDefinition = self.options.fields[key];
-
- var label = key;
- if (fieldDefinition.label)
- {
- label = fieldDefinition.label;
- }
-
- headers.push(label);
- }
- gridData.push(headers);
-
- for (var i = 0; i < self.data.length; i++)
- {
- var row = [];
- for (var key2 in self.data[i])
- {
- row.push(self.data[i][key2]);
- }
- gridData.push(row);
- }
-
- /*
- // TODO
- var gridData = [
- ["Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
- ["2009", 0, 2941, 4303, 354, 5814],
- ["2010", 5, 2905, 2867, 412, 5284],
- ["2011", 4, 2517, 4822, 552, 6127],
- ["2012", 2, 2422, 5399, 776, 4151]
- ];
- */
-
- var holder = $(self.container).find(".alpaca-container-grid-holder");
-
- var gridConfig = self.options.grid;
- gridConfig.data = gridData;
-
- $(holder).handsontable(gridConfig);
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.ControlField#getType
- */
- getType: function() {
- return "array";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.ControlField#getTitle
- */
- getTitle: function() {
- return "Grid Field";
- },
-
- /**
- * @see Alpaca.ControlField#getDescription
- */
- getDescription: function() {
- return "Renders array items into a grid";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("grid", Alpaca.Fields.GridField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ImageField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ImageField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "image";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Image Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Image Field.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("image", Alpaca.Fields.ImageField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IntegerField = Alpaca.Fields.NumberField.extend(
- /**
- * @lends Alpaca.Fields.IntegerField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.NumberField#getFieldType
- */
- getFieldType: function() {
- return "integer";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseInt(val, 10);
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- if (this.slider)
- {
- this.slider.slider("value", this.getValue());
- }
- },
-
- /**
- * @see Alpaca.Fields.NumberField#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- if (self.options.slider)
- {
- if (!Alpaca.isEmpty(self.schema.maximum) && !Alpaca.isEmpty(self.schema.minimum))
- {
- if (self.control)
- {
- self.control.after('');
-
- self.slider = $('#slider', self.control.parent()).slider({
- value: self.getValue(),
- min: self.schema.minimum,
- max: self.schema.maximum,
- slide: function(event, ui) {
- self.setValue(ui.value);
- self.refreshValidationState();
- }
- });
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Fields.NumberField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateInteger();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotAnInteger"),
- "status": status
- };
-
- return baseStatus;
- },
-
- /**
- * Validates if it is an integer.
- *
- * @returns {Boolean} true if it is an integer
- */
- _validateInteger: function()
- {
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid integer format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.integer, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getType
- */
- getType: function() {
- return "integer";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.NumberField#getTitle
- */
- getTitle: function() {
- return "Integer Field";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getDescription
- */
- getDescription: function() {
- return "Field for integers.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "integer"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "integer"
- },
- "divisibleBy": {
- "title": "Divisible By",
- "description": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "minimum": {
- "helper": "Minimum value of the field.",
- "type": "integer"
- },
- "maximum": {
- "helper": "Maximum value of the field.",
- "type": "integer"
- },
- "divisibleBy": {
- "helper": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "slider": {
- "title": "Slider",
- "description": "Generate jQuery UI slider control with the field if true.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "slider": {
- "rightLabel": "Slider control ?",
- "helper": "Generate slider control if selected.",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAnInteger": "This value is not an integer."
- });
- Alpaca.registerFieldClass("integer", Alpaca.Fields.IntegerField);
- Alpaca.registerDefaultSchemaFieldMapping("integer", "integer");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IPv4Field = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.IPv4Field.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "ipv4";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.ipv4;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"])
- {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidIPv4");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "IP Address Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "IP Address Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : Alpaca.regexps.ipv4;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "enum": ["ip-address"],
- "default":"ip-address",
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidIPv4": "Invalid IPv4 address, e.g. 192.168.0.1"
- });
- Alpaca.registerFieldClass("ipv4", Alpaca.Fields.IPv4Field);
- Alpaca.registerDefaultFormatFieldMapping("ip-address", "ipv4");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.JSONField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.JSONField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "json";
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- setValue: function(value)
- {
- if (Alpaca.isObject(value) || typeof(value) === "object")
- {
- value = JSON.stringify(value, null, 3);
- }
-
- this.base(value);
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (val && Alpaca.isString(val))
- {
- val = JSON.parse(val);
- }
-
- return val;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateJSON();
- valInfo["stringNotAJSON"] = {
- "message": status.status ? "" : this.view.getMessage("stringNotAJSON") +" "+ status.message,
- "status": status.status
- };
-
- return baseStatus && valInfo["stringNotAJSON"]["status"] ;
- },
-
- /**
- * Validates if it is a valid JSON object.
- * @returns {Boolean} true if it is a valid JSON object
- */
- _validateJSON: function()
- {
- var textValue = this.control.val();
-
- // allow null
- if (Alpaca.isValEmpty(textValue))
- {
- return {
- "status" : true
- };
- }
-
- // parse the string
- try
- {
- var obj = JSON.parse(textValue);
-
- // format the string as well
- this.setValue(JSON.stringify(obj, null, 3));
- return {
- "status" : true
- };
- }
- catch(e)
- {
- return {
- "status" : false,
- "message" : e.message
- };
- }
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // Some auto-formatting capabilities
- self.control.bind('keypress', function(e) {
-
- var code = e.keyCode || e.wich;
-
- if (code === 34) {
- self.control.insertAtCaret('"');
- }
- if (code === 123) {
- self.control.insertAtCaret('}');
- }
- if (code === 91) {
- self.control.insertAtCaret(']');
- }
- });
-
- self.control.bind('keypress', 'Ctrl+l', function() {
- self.getFieldEl().removeClass("alpaca-field-focused");
-
- // set class from state
- self.refreshValidationState();
- });
-
- self.control.attr('title','Type Ctrl+L to format and validate the JSON string.');
- }
-
- callback();
-
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "JSON Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Editor for JSON objects with basic validation and formatting.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAJSON": "This value is not a valid JSON string."
- });
-
- Alpaca.registerFieldClass("json", Alpaca.Fields.JSONField);
-
- $.fn.insertAtCaret = function (myValue) {
-
- return this.each(function() {
-
- //IE support
- if (document.selection) {
-
- this.focus();
- sel = document.selection.createRange();
- sel.text = myValue;
- this.focus();
-
- } else if (this.selectionStart || this.selectionStart == '0') { // jshint ignore:line
-
- //MOZILLA / NETSCAPE support
- var startPos = this.selectionStart;
- var endPos = this.selectionEnd;
- var scrollTop = this.scrollTop;
- this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
- this.focus();
- this.selectionStart = startPos /*+ myValue.length*/;
- this.selectionEnd = startPos /*+ myValue.length*/;
- this.scrollTop = scrollTop;
-
- } else {
-
- this.value += myValue;
- this.focus();
- }
- });
- };
-
- /*
- * jQuery Hotkeys Plugin
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- *
- * Based upon the plugin by Tzury Bar Yochay:
- * http://github.com/tzuryby/hotkeys
- *
- * Original idea by:
- * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
- */
- jQuery.hotkeys = {
- version: "0.8",
-
- specialKeys: {
- 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
- 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
- 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
- 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
- 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
- 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
- },
-
- shiftNums: {
- "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
- "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
- ".": ">", "/": "?", "\\": "|"
- }
- };
-
- function keyHandler( handleObj ) {
- // Only care when a possible input has been specified
- if ( typeof handleObj.data !== "string" ) {
- return;
- }
-
- var origHandler = handleObj.handler,
- keys = handleObj.data.toLowerCase().split(" ");
-
- handleObj.handler = function( event ) {
- // Don't fire in text-accepting inputs that we didn't directly bind to
- if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
- event.target.type === "text") ) {
- return;
- }
-
- // Keypress represents characters, not special keys
- var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
- character = String.fromCharCode( event.which ).toLowerCase(),
- key, modif = "", possible = {};
-
- // check combinations (alt|ctrl|shift+anything)
- if ( event.altKey && special !== "alt" ) {
- modif += "alt+";
- }
-
- if ( event.ctrlKey && special !== "ctrl" ) {
- modif += "ctrl+";
- }
-
- // TODO: Need to make sure this works consistently across platforms
- if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
- modif += "meta+";
- }
-
- if ( event.shiftKey && special !== "shift" ) {
- modif += "shift+";
- }
-
- if ( special ) {
- possible[ modif + special ] = true;
-
- } else {
- possible[ modif + character ] = true;
- possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
-
- // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
- if ( modif === "shift+" ) {
- possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
- }
- }
-
- for ( var i = 0, l = keys.length; i < l; i++ ) {
- if ( possible[ keys[i] ] ) {
- return origHandler.apply( this, arguments );
- }
- }
- };
- }
-
- jQuery.each([ "keydown", "keyup", "keypress" ], function() {
- jQuery.event.special[ this ] = { add: keyHandler };
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.LowerCaseField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.LowerCaseField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "lowercase";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var lowerValue = val.toLowerCase();
-
- if (lowerValue != this.getValue()) // jshint ignore:line
- {
- this.base(lowerValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Lowercase Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text field for lowercase text.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("lowercase", Alpaca.Fields.LowerCaseField);
- Alpaca.registerDefaultFormatFieldMapping("lowercase", "lowercase");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.MapField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.MapField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "map";
- },
-
- getType: function()
- {
- return "object"
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- // special handling - data can come in as an object, we convert to array
- if (this.data && Alpaca.isObject(this.data))
- {
- var newData = [];
-
- $.each(this.data, function(key, value) {
- var newValue = Alpaca.copyOf(value);
- newValue["_key"] = key;
- newData.push(newValue);
- });
-
- this.data = newData;
- }
-
- this.base();
-
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // special handling, convert back to object
- var o = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
- if (key)
- {
- delete v["_key"];
- o[key] = v;
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var isValidMapKeysNotEmpty = this._validateMapKeysNotEmpty();
- valInfo["keyMissing"] = {
- "message": isValidMapKeysNotEmpty ? "" : this.view.getMessage("keyMissing"),
- "status": isValidMapKeysNotEmpty
- };
-
- var isValidMapKeysUnique = this._validateMapKeysUnique();
- valInfo["keyNotUnique"] = {
- "message": isValidMapKeysUnique ? "" : this.view.getMessage("keyNotUnique"),
- "status": isValidMapKeysUnique
- };
-
- return baseStatus && valInfo["keyMissing"]["status"] && valInfo["keyNotUnique"]["status"];
- },
-
- /**
- * Validates that key fields are not empty.
- *
- * @returns {Boolean} true if keys are not empty
- */
- _validateMapKeysNotEmpty: function()
- {
- var isValid = true;
-
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (!key)
- {
- isValid = false;
- break;
- }
- }
-
- return isValid;
- },
-
- /**
- * Validates if key fields are unique.
- *
- * @returns {Boolean} true if keys are unique
- */
- _validateMapKeysUnique: function()
- {
- var isValid = true;
-
- var keys = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (keys[key])
- {
- isValid = false;
- }
-
- keys[key] = key;
- }
-
- return isValid;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "Map Field";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Field for objects with key/value pairs that share the same schema for values.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("map", Alpaca.Fields.MapField);
-
- // Additional Registrations
- Alpaca.registerMessages({
- "keyNotUnique": "Keys of map field are not unique.",
- "keyMissing": "Map contains an empty key."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PasswordField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PasswordField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "password";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.password;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPassword");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Password Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Password Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : /^[0-9a-zA-Z\x20-\x7E]*$/;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": this.schema.pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"password",
- "enum":["password"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPassword": "Invalid Password"
- });
- Alpaca.registerFieldClass("password", Alpaca.Fields.PasswordField);
- Alpaca.registerDefaultFormatFieldMapping("password", "password");
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PersonalNameField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PersonalNameField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "personalname";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var upperValue = "";
-
- for ( var i = 0; i < val.length; i++ )
- {
- if ( i === 0 )
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else if (val.charAt(i-1) === ' ' || val.charAt(i-1) === '-' || val.charAt(i-1) === "'")
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else
- {
- upperValue += val.charAt(i);
- }
- }
-
- if (upperValue != this.getValue()) // jshint ignore:line
- {
- this.base(upperValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Personal Name";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text Field for personal name with captical letter for first letter & after hyphen, space or apostrophe.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("personalname", Alpaca.Fields.PersonalNameField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PhoneField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PhoneField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "tel";
- this.inputType = "tel";
-
- this.base();
-
- if (!this.schema.pattern) {
- this.schema.pattern = Alpaca.regexps.phone;
- }
-
- if (Alpaca.isEmpty(this.options.maskString)) {
- this.options.maskString = "(999) 999-9999";
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPhone");
- }
-
- return baseStatus;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "phone";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Phone Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Phone Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.phone;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"phone",
- "enum":["phone"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "maskString": {
- "title": "Field Mask String",
- "description": "Expression for field mask",
- "type": "string",
- "default": "(999) 999-9999"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPhone": "Invalid Phone Number, e.g. (123) 456-9999"
- });
- Alpaca.registerFieldClass("phone", Alpaca.Fields.PhoneField);
- Alpaca.registerDefaultFormatFieldMapping("phone", "phone");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SearchField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.SearchField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "search";
- this.inputType = "search";
-
- this.base();
-
- this.options.attributes.results = 5;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "search";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Search Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A search box field";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("search", Alpaca.Fields.SearchField);
- Alpaca.registerDefaultSchemaFieldMapping("search", "search");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.usHoldings = {};
-
- Alpaca.usHoldings.territories = {
- "American Samoa" : "AS",
- "District Of Columbia" : "DC",
- "Federated States Of Micronesia" : "FM",
- "Guam" : "GU",
- "Marshall Islands" : "MH",
- "Northern Mariana Islands" : "MP",
- "Palau" : "PW",
- "Puerto Rico" : "PR",
- "Virgin Islands" : "VI"
- };
-
- Alpaca.usHoldings.states = {
- "Alabama" : "AL",
- "Alaska" : "AK",
- "Arizona" : "AZ",
- "Arkansas" : "AR",
- "California" : "CA",
- "Colorado" : "CO",
- "Connecticut" : "CT",
- "Delaware" : "DE",
- "Florida" : "FL",
- "Georgia" : "GA",
- "Hawaii" : "HI",
- "Idaho" : "ID",
- "Illinois" : "IL",
- "Indiana" : "IN",
- "Iowa" : "IA",
- "Kansas" : "KS",
- "Kentucky" : "KY",
- "Louisiana" : "LA",
- "Maine" : "ME",
- "Maryland" : "MD",
- "Massachusetts" : "MA",
- "Michigan" : "MI",
- "Minnesota" : "MN",
- "Mississippi" : "MS",
- "Missouri" : "MO",
- "Montana" : "MT",
- "Nebraska" : "NE",
- "Nevada" : "NV",
- "New Hampshire" : "NH",
- "New Jersey" : "NJ",
- "New Mexico" : "NM",
- "New York" : "NY",
- "North Carolina" : "NC",
- "North Dakota" : "ND",
- "Ohio" : "OH",
- "Oklahoma" : "OK",
- "Oregon" : "OR",
- "Pennsylvania" : "PA",
- "Rhode Island" : "RI",
- "South Carolina" : "SC",
- "South Dakota" : "SD",
- "Tennessee" : "TN",
- "Texas" : "TX",
- "Utah" : "UT",
- "Vermont" : "VT",
- "Virginia" : "VA",
- "Washington" : "WA",
- "West Virginia" : "WV",
- "Wisconsin" : "WI",
- "Wyoming" : "WY"
- };
-
- Alpaca.Fields.StateField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.StateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "state";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize)) {
- this.options.capitalize = false;
- }
- if (Alpaca.isUndefined(this.options.includeStates)) {
- this.options.includeStates = true;
- }
- if (Alpaca.isUndefined(this.options.includeTerritories)) {
- this.options.includeTerritories = true;
- }
- if (Alpaca.isUndefined(this.options.format)) {
- this.options.format = "name";
- }
-
- // validate settings
- if (this.options.format === "name" || this.options.format === "code")
- {
- // valid formats
- }
- else
- {
- Alpaca.logError("The configured state format: " + this.options.format + " is not a legal value [name, code]");
-
- // default to name format
- this.options.format = "name";
- }
-
- // configure
- var holdings = Alpaca.retrieveUSHoldings(
- this.options.includeStates,
- this.options.includeTerritories,
- (this.options.format === "code"),
- this.options.capitalize);
-
- this.schema["enum"] = holdings.keys;
- this.options.optionLabels = holdings.values;
-
- this.base();
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "State Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of states and/or territories in the United States, keyed by their two-character code.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "How to represent the state values in the selector",
- "type": "string",
- "default": "name",
- "enum":["name", "code"],
- "readonly": true
- },
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- },
- "includeStates": {
- "title": "Include States",
- "description": "Whether to include the states of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- },
- "includeTerritories": {
- "title": "Include Territories",
- "description": "Whether to include the territories of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- },
- "capitalize": {
- "type": "checkbox"
- },
- "includeStates": {
- "type": "checkbox"
- },
- "includeTerritories": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("state", Alpaca.Fields.StateField);
- Alpaca.registerDefaultFormatFieldMapping("state", "state");
-
- /**
- * Helper function to retrieve the holdings of US states and territories.
- *
- * @param {Boolean} includeStates whether to include US states
- * @param {Boolean} includeTerritories whether to include US territories
- * @param {Boolean} codeValue whether to hand back US holding codes (instead of names)
- * @param {Boolean} capitalize whether to capitalize the values handed back
- *
- * @returns {Object} an object containing "keys" and "values", both of which are arrays.
- */
- Alpaca.retrieveUSHoldings = (function()
- {
- return function(includeStates, includeTerritories, codeValue, capitalize) {
- var res = {
- keys: [],
- values: []
- };
- var opts = $.extend(
- {},
- includeStates ? Alpaca.usHoldings.states : {},
- includeTerritories ? Alpaca.usHoldings.territories : {}
- );
- var sorted = Object.keys(opts);
- sorted.sort();
- for (var i in sorted) {
- var state = sorted[i];
- var key = opts[state];
- var value = codeValue ? key : state;
- if (capitalize) {
- value = value.toUpperCase();
- }
- res.keys.push(key);
- res.values.push(value);
- }
- return res;
- };
- })();
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- /**
- * The table field is used for data representations that consist of an array with objects inside of it. The objects
- * must have a uniform structure. The table field renders a standard HTML table using the table. The individual
- * columns are either editable (in edit mode) or simply displayed in read-only mode.
- */
- Alpaca.Fields.TableField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.TableField.prototype
- */
- {
- setup: function()
- {
- var self = this;
-
- if (!self.options)
- {
- self.options = {};
- }
-
- if (typeof(self.options.animate) === "undefined")
- {
- self.options.animate = false;
- }
-
- this.base();
-
- if (!this.options.items.type)
- {
- this.options.items.type = "tablerow";
- }
-
- // support for either "datatable" or "datatables"
- if (this.options.datatable) {
- this.options.datatables = this.options.datatable;
- }
-
- // assume empty options for datatables
- if (typeof(this.options.datatables) === "undefined")
- {
- this.options.datatables = {
- "paging": false,
- "lengthChange": false,
- "info": false,
- "searching": false,
- "ordering": true
- };
- }
-
- // assume actions column to be shown
- if (typeof(this.options.showActionsColumn) === "undefined")
- {
- this.options.showActionsColumn = true;
-
- if (this.options.readonly)
- {
- this.options.showActionsColumn = false;
- }
-
- if (this.isDisplayOnly())
- {
- this.options.showActionsColumn = false;
- }
- }
- },
-
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "table";
- },
-
- /**
- * The table field uses the "array" container convention to render the DOM. As such, nested objects are wrapped
- * in "field" elements that result in slightly incorrect table structures. Part of the reason for this is that
- * browsers are very fussy when it comes to injection of nested TR or TD partials. Here, we generate most
- * things as DIVs and then do some cleanup in this method to make sure that the table is put togehter in the
- * right way.
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- self.cleanupDomInjections();
-
- // apply styles of underlying "table"
- var table = $(this.container).find("table");
- self.applyStyle("table", table);
-
- // if the DataTables plugin is available, use it
- if (self.options.datatables)
- {
- if ($.fn.DataTable)
- {
- $(this.container).find("table").DataTable(self.options.datatables);
- }
- }
-
- callback();
-
- }.bind(self));
- },
-
- cleanupDomInjections: function()
- {
- /**
- * Takes a DOM element and merges it "up" to the parent element. Data attributes and some classes are
- * copied from DOM element into the parent element. The children of the DOM element are added to the
- * parent and the DOM element is removed.
- *
- * @param mergeElement
- */
- var mergeElementUp = function(mergeElement)
- {
- var mergeElementParent = $(mergeElement).parent();
- var mergeElementChildren = $(mergeElement).children();
-
- // copy merge element classes to parent
- var classNames =$(mergeElement).attr('class').split(/\s+/);
- $.each( classNames, function(index, className){
- if (className === "alpaca-merge-up") {
- // skip
- } else {
- $(mergeElementParent).addClass(className);
- }
- });
-
- // copy attributes to TR
- $.each($(mergeElement)[0].attributes, function() {
- if (this.name && this.name.indexOf("data-") === 0)
- {
- $(mergeElementParent).attr(this.name, this.value);
- }
- });
-
- // replace field with children
- if (mergeElementChildren.length > 0)
- {
- $(mergeElement).replaceWith(mergeElementChildren);
- }
- else
- {
- $(mergeElement).remove();
- }
- };
-
- // find each TR's .alpaca-field and merge up
- this.getFieldEl().find("tr > .alpaca-field").each(function() {
- mergeElementUp(this);
- });
-
- // find each TR's .alpaca-container and merge up
- this.getFieldEl().find("tr > .alpaca-container").each(function() {
- mergeElementUp(this);
- });
-
- // find the action bar and slip a TD around it
- var alpacaArrayActionbar = this.getFieldEl().find("." + Alpaca.MARKER_CLASS_ARRAY_ITEM_ACTIONBAR);
- if (alpacaArrayActionbar.length > 0)
- {
- alpacaArrayActionbar.each(function() {
- var td = $("\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function l(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}function c(){var e="";return e}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-any"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s,l="",c=i.helperMissing;return l+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-checkbox"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s,l="",c=i.helperMissing;return l+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-image"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function",c=this.escapeExpression;return s+=''},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-radio"]=function(e,t,i,a,n){function r(e,t,a){var n,r,s,l="";return l+="\n ",r=i.compare||e&&e.compare,s={hash:{},inverse:d.noop,fn:d.program(2,o,t),data:t},n=r?r.call(e,e&&e.value,a&&a.data,s):p.call(e,"compare",e&&e.value,a&&a.data,s),(n||0===n)&&(l+=n),l+="\n "}function o(e,t){var a,n,r="";return r+="\n ",(n=i.text)?a=n.call(e,{hash:{},data:t}):(n=e&&e.text,a=typeof n===c?n.call(e,{hash:{},data:t}):n),(a||0===a)&&(r+=a),r+="\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var s,l="",c="function",d=this,p=i.helperMissing;return l+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-select"]=function(e,t,i,a,n){function r(e,t,a){var n,r,s,l="";return l+="\n ",r=i.compare||e&&e.compare,s={hash:{},inverse:d.noop,fn:d.program(2,o,t),data:t},n=r?r.call(e,e&&e.value,a&&a.data,s):p.call(e,"compare",e&&e.value,a&&a.data,s),(n||0===n)&&(l+=n),l+="\n "}function o(e,t){var a,n,r="";return r+="\n ",(n=i.text)?a=n.call(e,{hash:{},data:t}):(n=e&&e.text,a=typeof n===c?n.call(e,{hash:{},data:t}):n),(a||0===a)&&(r+=a),r+="\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var s,l="",c="function",d=this,p=i.helperMissing;return l+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-text"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-textarea"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-url"]=function(e,t,i,a,n){function r(e){var t,i="";return i+='target="'+f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTarget,typeof t===h?t.apply(e):t))+'"'}function o(e){var t;return f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTitle,typeof t===h?t.apply(e):t))}function s(e,t){var a,n;return(n=i.data)?a=n.call(e,{hash:{},data:t}):(n=e&&e.data,a=typeof n===h?n.call(e,{hash:{},data:t}):n),f(a)}function l(e){var t,i="";return i+="\n "+f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTitle,typeof t===h?t.apply(e):t))+"\n "}function c(e,t){var a,n,r="";return r+="\n ",(n=i.data)?a=n.call(e,{hash:{},data:t}):(n=e&&e.data,a=typeof n===h?n.call(e,{hash:{},data:t}):n),r+=f(a)+"\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u="",h="function",f=this.escapeExpression,m=this;return u+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"].control=function(e,t,i,a,n){function r(e,t){var a,n,r="";return r+='\n \n "}function o(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.labelClass,typeof t===f?t.apply(e):t))}function s(){var e="";return e}function l(e,t){var a,n="";return n+='\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function c(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"].form=function(e,t,i,a,n){function r(){var e="";return e}function o(e,t,a){var n,r="";return r+="\n ",n=i.each.call(e,(n=e&&e.options,null==n||n===!1?n:n.buttons),{hash:{},inverse:v.noop,fn:v.programWithDepth(4,s,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n "}function s(e,t,a){var n,r,o,s="";return s+='\n \n "}function l(){return'type="submit"'}function c(){return'type="reset"'}function d(e,t){var a,n,r="";return r+=g((a=null==t||t===!1?t:t.key,typeof a===m?a.apply(e):a))+'="',(n=i.value)?a=n.call(e,{hash:{},data:t}):(n=e&&e.value,a=typeof n===m?n.call(e,{hash:{},data:t}):n),r+=g(a)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var p,u,h,f="",m="function",g=this.escapeExpression,v=this,b=i.helperMissing,y=i.blockHelperMissing;return f+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["container-array-actionbar"]=function(e,t,i,a,n){function r(e,t,a){var n,r,l="";return l+='\n \n "}function o(e){var t,i="";return i+='\n \n '}function s(e,t){var a,n;return(n=i.label)?a=n.call(e,{hash:{},data:t}):(n=e&&e.label,a=typeof n===p?n.call(e,{hash:{},data:t}):n),a||0===a?a:""}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var l,c,d="",p="function",u=this.escapeExpression,h=this;return d+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["container-array-item"]=function(e,t,i,a,n){function r(e,t){var a,n,r,s="";return s+='\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function l(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}function c(){var e="";return e}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["control-any"]=function(e,t,i,a,n){function r(){return'readonly="readonly"'}function o(e,t){var a,n,r="";return r+='name="',(n=i.name)?a=n.call(e,{hash:{},data:t}):(n=e&&e.name,a=typeof n===p?n.call(e,{hash:{},data:t}):n),r+=u(a)+'"'}function s(e,t){var i,a="";return a+="data-"+u((i=null==t||t===!1?t:t.key,typeof i===p?i.apply(e):i))+'="'+u(typeof e===p?e.apply(e):e)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var l,c,d="",p="function",u=this.escapeExpression,h=this;return d+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["control-checkbox"]=function(e,t,i,a,n){function r(e,t,a){var n,r="";return r+="\n\n ",n=i.each.call(e,e&&e.checkboxOptions,{hash:{},inverse:m.noop,fn:m.programWithDepth(2,o,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n\n "}function o(e,t,a){var n,r,o="";return o+='\n\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n " -}function c(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].form=function(e,t,i,a,n){function r(){var e="";return e}function o(e,t,a){var n,r="";return r+="\n ",n=i.each.call(e,(n=e&&e.options,null==n||n===!1?n:n.buttons),{hash:{},inverse:m.noop,fn:m.programWithDepth(4,s,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n "}function s(e,t,a){var n,r,o="";return o+='\n \n "}function l(e,t){var a,n,r="";return r+=f((a=null==t||t===!1?t:t.key,typeof a===h?a.apply(e):a))+'="',(n=i.value)?a=n.call(e,{hash:{},data:t}):(n=e&&e.value,a=typeof n===h?n.call(e,{hash:{},data:t}):n),r+=f(a)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var c,d,p,u="",h="function",f=this.escapeExpression,m=this,g=i.blockHelperMissing;return u+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].message=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].wizard=function(e,t,i,a,n){function r(e,t){var a,n="";return n+='\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-image"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-radio"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-select"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-text"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-textarea"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-url"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "target=\"" - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTarget)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\""; - return buffer; - } - -function program3(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program5(depth0,data) { - - var stack1, helper; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - return escapeExpression(stack1); - } - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n " - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\n "; - return buffer; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\n "; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program4(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program6(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper, options; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - - return "type=\"submit\""; - } - -function program7(depth0,data) { - - - return "type=\"reset\""; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-actionbar"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } - -function program4(depth0,data) { - - var stack1, helper; - if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { return stack1; } - else { return ''; } - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-item"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper, options; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - - return "readonly=\"readonly\""; - } - -function program3(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "name=\""; - if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "data-" - + escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\"" - + escapeExpression((typeof depth0 === functionType ? depth0.apply(depth0) : depth0)) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n\n "; - stack1 = helpers.each.call(depth0, (depth0 && depth0.checkboxOptions), {hash:{},inverse:self.noop,fn:self.programWithDepth(2, program2, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - return buffer; - } -function program2(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n
- *
- * Alpaca(el, config);
- *
- *
- *
- * The full syntax is:
- *
- *
- *
- * Alpaca(el, {
- * "data" : {Any} field data (optional),
- * "schema": {Object} field schema (optional),
- * "options" : {Object} field options (optional),
- * "view": {Object|String} field view (object or id reference) (optional),
- * "render": {Function} callback function for replacing default rendering method (optional),
- * "postRender": {Function} callback function for post-rendering (optional),
- * "error": {Function} callback function for error handling (optional),
- * "connector": {Alpaca.Connector} connector for retrieving or storing data, schema, options, view and templates. (optional)
- * });
- *
- *
- *
- * @returns {*}
- */
- var Alpaca = function()
- {
- var args = Alpaca.makeArray(arguments);
- if (args.length === 0) {
- // illegal
- return Alpaca.throwDefaultError("You must supply at least one argument. This argument can either be a DOM element against which Alpaca will generate a form or it can be a function name. See http://www.alpacajs.org for more details.");
- }
-
- // element is the first argument (either a string or a DOM element)
- var el = args[0];
- if (el && Alpaca.isString(el)) {
- el = $("#" + el);
- }
-
- // other arguments we may want to figure out
- var data = null;
- var schema = null;
- var options = null;
- var view = null;
- var callback = null;
- var renderedCallback = null;
- var errorCallback = null;
- var connector = null;
- var notTopLevel = false;
- var initialSettings = {};
-
- // if these options are provided, then data, schema, options and source are loaded via connector
- var dataSource = null;
- var schemaSource = null;
- var optionsSource = null;
- var viewSource = null;
-
- // hands back the field instance that is bound directly under the element el
- var findExistingAlpacaBinding = function()
- {
- var existing = null;
-
- var topElements = $(el).find(":first");
- if (topElements.length > 0)
- {
- // does a field binding exist?
- var fieldId = $(topElements[0]).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var _existing = Alpaca.fieldInstances[fieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- else
- {
- // does a form binding exist?
- var formId = $(topElements[0]).attr("data-alpaca-form-id");
- if (formId)
- {
- var subElements = $(topElements[0]).find(":first");
- if (subElements.length > 0)
- {
- var subFieldId = $(subElements[0]).attr("data-alpaca-field-id");
- if (subFieldId)
- {
- var _existing = Alpaca.fieldInstances[subFieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- }
- }
- }
- }
-
- return existing;
- };
-
- var specialFunctionNames = ["get", "exists", "destroy"];
- var isSpecialFunction = (args.length > 1 && Alpaca.isString(args[1]) && (specialFunctionNames.indexOf(args[1]) > -1));
-
- var existing = findExistingAlpacaBinding();
- if (existing || isSpecialFunction)
- {
- if (isSpecialFunction)
- {
- // second argument must be a special function name
- var specialFunctionName = args[1];
- if ("get" === specialFunctionName) {
- return existing;
- }
- else if ("exists" === specialFunctionName) {
- return (existing ? true : false);
- }
- else if ("destroy" === specialFunctionName) {
- existing.destroy();
- return;
- }
-
- return Alpaca.throwDefaultError("Unknown special function: " + specialFunctionName);
- }
-
- return existing;
- }
- else
- {
- var config = null;
-
- // just a dom element, no other args?
- if (args.length === 1)
- {
- // grab the data inside of the element and use that for config
- var jsonString = $(el).text();
-
- config = JSON.parse(jsonString);
- $(el).html("");
- }
- else
- {
- if (Alpaca.isObject(args[1]))
- {
- config = args[1];
- }
- else if (Alpaca.isFunction(args[1]))
- {
- config = args[1]();
- }
- else
- {
- config = {
- "data": args[1]
- };
- }
- }
-
- if (!config)
- {
- return Alpaca.throwDefaultError("Unable to determine Alpaca configuration");
- }
-
- data = config.data;
- schema = config.schema;
- options = config.options;
- view = config.view;
- callback = config.render;
- if (config.callback) {
- callback = config.callback;
- }
- renderedCallback = config.postRender;
- errorCallback = config.error;
- connector = config.connector;
-
- // sources
- dataSource = config.dataSource;
- schemaSource = config.schemaSource;
- optionsSource = config.optionsSource;
- viewSource = config.viewSource;
-
- // other
- if (config.ui) {
- initialSettings["ui"] = config.ui;
- }
- if (config.type) {
- initialSettings["type"] = config.type;
- }
- if (!Alpaca.isEmpty(config.notTopLevel)) {
- notTopLevel = config.notTopLevel;
- }
- }
-
- // if no error callback is provided, we fall back to a browser alert
- if (Alpaca.isEmpty(errorCallback)) {
- errorCallback = Alpaca.defaultErrorCallback;
- }
-
- if (Alpaca.isEmpty(connector)) {
- var ConnectorClass = Alpaca.getConnectorClass("default");
- connector = new ConnectorClass("default");
- }
-
- // For second or deeper level of fields, default loader should be the one to do loadAll
- // since schema, data, options and view should have already been loaded.
- // Unless we want to load individual fields (other than the templates) using the provided
- // loader, this should be good enough. The benefit is saving time on loader format checking.
-
- var loadAllConnector = connector;
-
- if (notTopLevel) {
- var LoadAllConnectorClass = Alpaca.getConnectorClass("default");
- loadAllConnector = new LoadAllConnectorClass("default");
- }
-
- if (!options) {
- options = {};
- }
-
- // resets the hideInitValidationError back to default state after first render
- var _resetInitValidationError = function(field)
- {
- // if this is the top-level alpaca field, then we call for validation state to be recalculated across
- // all child fields
- if (!field.parent)
- {
- // final call to update validation state
- // only do this if we're not supposed to suspend initial validation errors
- if (!field.hideInitValidationError)
- {
- field.refreshValidationState(true);
- }
-
- // force hideInitValidationError to false for field and all children
- if (field.view.type !== 'view')
- {
- Alpaca.fieldApplyFieldAndChildren(field, function(field) {
-
- // set to false after first validation (even if in CREATE mode, we only force init validation error false on first render)
- field.hideInitValidationError = false;
-
- });
- }
- }
- };
-
- // wrap rendered callback to allow for UI treatment (dom focus, etc)
- var _renderedCallback = function(field)
- {
- // if top level, apply a unique observable scope id
- if (!field.parent)
- {
- field.observableScope = Alpaca.generateId();
- }
-
- // if top level and focus has not been specified, then auto-set
- if (Alpaca.isUndefined(options.focus) && !field.parent) {
- options.focus = Alpaca.defaultFocus;
- }
-
- // auto-set the focus?
- if (options && options.focus)
- {
- window.setTimeout(function() {
-
- var doFocus = function(__field)
- {
- __field.suspendBlurFocus = true;
- __field.focus();
- __field.suspendBlurFocus = false;
- };
-
- if (options.focus)
- {
- if (field.isControlField && field.isAutoFocusable())
- {
- // just focus on this one
- doFocus(field);
- }
- else if (field.isContainerField)
- {
- // if focus = true, then focus on the first child control if it is auto-focusable
- // and not read-only
- if (options.focus === true)
- {
- // pick first element in form
- if (field.children && field.children.length > 0)
- {
- for (var z = 0; z < field.children.length; z++)
- {
- if (field.children[z].isControlField)
- {
- if (field.children[z].isAutoFocusable() && !field.children[z].options.readonly)
- {
- doFocus(field.children[z]);
- break;
- }
- }
- }
- }
- }
- else if (typeof(options.focus) === "string")
- {
- // assume it is a path to the child
- var child = field.getControlByPath(options.focus);
- if (child && child.isControlField && child.isAutoFocusable())
- {
- doFocus(child);
- }
- }
- }
-
- _resetInitValidationError(field);
- }
- }, 500);
- }
- else
- {
- _resetInitValidationError(field);
- }
-
- if (renderedCallback)
- {
- renderedCallback(field);
- }
- };
-
- loadAllConnector.loadAll({
- "data": data,
- "schema": schema,
- "options": options,
- "view": view,
- "dataSource": dataSource,
- "schemaSource": schemaSource,
- "optionsSource": optionsSource,
- "viewSource": viewSource
- }, function(loadedData, loadedOptions, loadedSchema, loadedView) {
-
- // for cases where things could not be loaded via source loaders, fall back to what may have been passed
- // in directly as values
-
- loadedData = loadedData ? loadedData : data;
- loadedSchema = loadedSchema ? loadedSchema: schema;
- loadedOptions = loadedOptions ? loadedOptions : options;
- loadedView = loadedView ? loadedView : view;
-
- // some defaults for the case where data is null
- // if schema + options are not provided, we assume a text field
-
- if (Alpaca.isEmpty(loadedData))
- {
- if (Alpaca.isEmpty(loadedSchema) && (Alpaca.isEmpty(loadedOptions) || Alpaca.isEmpty(loadedOptions.type)))
- {
- loadedData = "";
-
- if (Alpaca.isEmpty(loadedOptions))
- {
- loadedOptions = "text";
- }
- else if (options && Alpaca.isObject(options))
- {
- loadedOptions.type = "text";
- }
- }
- }
-
- if (loadedOptions.view)
- {
- loadedView = loadedOptions.view;
- }
-
- // init alpaca
- return Alpaca.init(el, loadedData, loadedOptions, loadedSchema, loadedView, initialSettings, callback, _renderedCallback, connector, errorCallback);
-
- }, function (loadError) {
- errorCallback(loadError);
- return null;
- });
- };
-
- /**
- * @namespace Namespace for all Alpaca Field Class Implementations.
- */
- Alpaca.Fields = { };
-
- /**
- * @namespace Namespace for all Alpaca Connector Class Implementations.
- */
- Alpaca.Connectors = { };
-
- Alpaca.Extend = $.extend;
-
- Alpaca.Create = function()
- {
- var args = Array.prototype.slice.call(arguments);
- args.unshift({});
-
- return $.extend.apply(this, args);
- };
-
- // static methods and properties
- Alpaca.Extend(Alpaca,
- /** @lends Alpaca */
- {
- /**
- * Makes an array.
- *
- * @param {Any} nonArray A non-array variable.
- * @returns {Array} Array out of the non-array variable.
- */
- makeArray : function(nonArray) {
- return Array.prototype.slice.call(nonArray);
- },
-
- /**
- * Finds whether the type of a variable is function.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a function, false otherwise.
- */
- isFunction: function(obj) {
- return Object.prototype.toString.call(obj) === "[object Function]";
- },
-
- /**
- * Finds whether the type of a variable is string.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a string, false otherwise.
- */
- isString: function(obj) {
- return (typeof obj === "string");
- },
-
- /**
- * Finds whether the type of a variable is object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an object, false otherwise.
- */
- isObject: function(obj) {
- return !Alpaca.isUndefined(obj) && Object.prototype.toString.call(obj) === '[object Object]';
- },
-
- /**
- * Finds whether the type of a variable is a plain, non-prototyped object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a plain object, false otherwise.
- */
- isPlainObject: function(obj) {
- return $.isPlainObject(obj);
- },
-
- /**
- * Finds whether the type of a variable is number.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a number, false otherwise.
- */
- isNumber: function(obj) {
- return (typeof obj === "number");
- },
-
- /**
- * Finds whether the type of a variable is array.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an array, false otherwise.
- */
- isArray: function(obj) {
- return obj instanceof Array;
- },
-
- /**
- * Finds whether the type of a variable is boolean.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a boolean, false otherwise.
- */
- isBoolean: function(obj) {
- return (typeof obj === "boolean");
- },
-
- /**
- * Finds whether the type of a variable is undefined.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a undefined, false otherwise.
- */
- isUndefined: function(obj) {
- return (typeof obj == "undefined");
- },
-
- /**
- * Strips any excess whitespace characters from the given text.
- * Returns the trimmed string.
- *
- * @param str
- *
- * @return trimmed string
- */
- trim: function(text)
- {
- var trimmed = text;
-
- if (trimmed && Alpaca.isString(trimmed))
- {
- trimmed = trimmed.replace(/^\s+|\s+$/g, '');
- }
-
- return trimmed;
- },
-
- /**
- * Provides a safe conversion of an HTML textual string into a DOM object.
- *
- * @param x
- * @return {*}
- */
- safeDomParse: function(x)
- {
- if (x && Alpaca.isString(x))
- {
- x = Alpaca.trim(x);
-
- // convert to dom
- var converted = null;
- try
- {
- converted = $(x);
- }
- catch (e)
- {
- // make another attempt to account for safety in some browsers
- x = "displayReadonly
attribute set to false, the read-only field will not appear.",
- "type": "boolean",
- "default": false
- },
- "required": {
- "title": "Required",
- "description": "Indicates whether the field's value is required. If set to true, the field must take on a valid value and cannnot be left empty or unassigned.",
- "type": "boolean",
- "default": false
- },
- "default": {
- "title": "Default",
- "description": "The default value to be assigned for this property. If the data for the field is empty or not provided, this default value will be plugged in for you. Specify a default value when you want to pre-populate the field's value ahead of time.",
- "type": "any"
- },
- "type": {
- "title": "Type",
- "description": "Data type of the property.",
- "type": "string",
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Data format of the property.",
- "type": "string"
- },
- "disallow": {
- "title": "Disallowed Values",
- "description": "List of disallowed values for the property.",
- "type": "array"
- },
- "dependencies": {
- "title": "Dependencies",
- "description": "List of property dependencies.",
- "type": "array"
- }
- }
- };
- if (this.getType && !Alpaca.isValEmpty(this.getType())) {
- schemaOfSchema.properties.type['default'] = this.getType();
- schemaOfSchema.properties.type['enum'] = [this.getType()];
- }
- return schemaOfSchema;
- },
-
- /**
- * Returns Alpaca options for the schema properties that managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the schema properties that are managed by this class.
- */
- getOptionsForSchema: function() {
- return {
- "fields": {
- "title": {
- "helper": "Field short description",
- "type": "text"
- },
- "description": {
- "helper": "Field detailed description",
- "type": "textarea"
- },
- "readonly": {
- "helper": "Field will be read only if checked",
- "rightLabel": "This field is read-only",
- "type": "checkbox"
- },
- "required": {
- "helper": "Field value must be set if checked",
- "rightLabel": "This field is required",
- "type": "checkbox"
- },
- "default": {
- "helper": "Field default value",
- "type": "textarea"
- },
- "type": {
- "helper": "Field data type",
- "type": "text"
- },
- "format": {
- "type": "select",
- "dataSource": function(callback) {
- for (var key in Alpaca.defaultFormatFieldMapping)
- {
- this.selectOptions.push({
- "value": key,
- "text": key
- });
- }
-
- callback();
- }
- },
- "disallow": {
- "helper": "Disallowed values for the field",
- "itemLabel":"Value",
- "type": "array"
- },
- "dependencies": {
- "helper": "Field Dependencies",
- "multiple":true,
- "size":3,
- "type": "select",
- "dataSource": function (field, callback) {
- if (field.parent && field.parent.schemaParent && field.parent.schemaParent.parent) {
- for (var key in field.parent.schemaParent.parent.childrenByPropertyId) {
- if (key != field.parent.schemaParent.propertyId) { // jshint ignore:line
- field.selectOptions.push({
- "value": key,
- "text": key
- });
- }
- }
- }
- if (callback) {
- callback();
- }
- }
- }
- }
- };
- },
-
- /**
- * Returns JSON schema of the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} JSON schema of the Alpaca options that are managed by this class.
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = {
- "title": "Options for " + this.getTitle(),
- "description": this.getDescription() + " (Options)",
- "type": "object",
- "properties": {
- "form":{},
- "id": {
- "title": "Field Id",
- "description": "Unique field id. Auto-generated if not provided.",
- "type": "string"
- },
- "type": {
- "title": "Field Type",
- "description": "Field type.",
- "type": "string",
- "default": this.getFieldType(),
- "readonly": true
- },
- "validate": {
- "title": "Validation",
- "description": "Field validation is required if true.",
- "type": "boolean",
- "default": true
- },
- "showMessages": {
- "title": "Show Messages",
- "description": "Display validation messages if true.",
- "type": "boolean",
- "default": true
- },
- "disabled": {
- "title": "Disabled",
- "description": "Field will be disabled if true.",
- "type": "boolean",
- "default": false
- },
- "readonly": {
- "title": "Readonly",
- "description": "Field will be readonly if true.",
- "type": "boolean",
- "default": false
- },
- "hidden": {
- "title": "Hidden",
- "description": "Field will be hidden if true.",
- "type": "boolean",
- "default": false
- },
- "label": {
- "title": "Label",
- "description": "Field label.",
- "type": "string"
- },
- "helper": {
- "title": "Helper",
- "description": "Field help message.",
- "type": "string"
- },
- "fieldClass": {
- "title": "CSS class",
- "description": "Specifies one or more CSS classes that should be applied to the dom element for this field once it is rendered. Supports a single value, comma-delimited values, space-delimited values or values passed in as an array.",
- "type": "string"
- },
- "hideInitValidationError" : {
- "title": "Hide Initial Validation Errors",
- "description" : "Hide initial validation errors if true.",
- "type": "boolean",
- "default": false
- },
- "focus": {
- "title": "Focus",
- "description": "If true, the initial focus for the form will be set to the first child element (usually the first field in the form). If a field name or path is provided, then the specified child field will receive focus. For example, you might set focus to 'name' (selecting the 'name' field) or you might set it to 'client/name' which picks the 'name' field on the 'client' object.",
- "type": "checkbox",
- "default": true
- },
- "optionLabels": {
- "title": "Enumerated Value Labels",
- "description": "An array of string labels for items in the enum array",
- "type": "array"
- },
- "view": {
- "title": "Override of the view for this field",
- "description": "Allows for this field to be rendered with a different view (such as 'display' or 'create')",
- "type": "string"
- }
- }
- };
- if (this.isTopLevel()) {
-
- schemaOfOptions.properties.form = {
- "title": "Form",
- "description": "Options for rendering the FORM tag.",
- "type": "object",
- "properties": {
- "attributes": {
- "title": "Form Attributes",
- "description": "List of attributes for the FORM tag.",
- "type": "object",
- "properties": {
- "id": {
- "title": "Id",
- "description": "Unique form id. Auto-generated if not provided.",
- "type": "string"
- },
- "action": {
- "title": "Action",
- "description": "Form submission endpoint",
- "type": "string"
- },
- "method": {
- "title": "Method",
- "description": "Form submission method",
- "enum":["post","get"],
- "type": "string"
- },
- "rubyrails": {
- "title": "Ruby On Rails",
- "description": "Ruby on Rails Name Standard",
- "enum": ["true", "false"],
- "type": "string"
- },
- "name": {
- "title": "Name",
- "description": "Form name",
- "type": "string"
- },
- "focus": {
- "title": "Focus",
- "description": "Focus Setting",
- "type": "any"
- }
- }
- },
- "buttons": {
- "title": "Form Buttons",
- "description": "Configuration for form-bound buttons",
- "type": "object",
- "properties": {
- "submit": {
- "type": "object",
- "title": "Submit Button",
- "required": false
- },
- "reset": {
- "type": "object",
- "title": "Reset button",
- "required": false
- }
- }
- },
- "toggleSubmitValidState": {
- "title": "Toggle Submit Valid State",
- "description": "Toggle the validity state of the Submit button",
- "type": "boolean",
- "default": true
- }
- }
- };
-
- } else {
- delete schemaOfOptions.properties.form;
- }
-
- return schemaOfOptions;
- },
-
- /**
- * Returns Alpaca options for the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the Alpaca options that are managed by this class.
- */
- getOptionsForOptions: function() {
- var optionsForOptions = {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "type": {
- "type": "text"
- },
- "validate": {
- "rightLabel": "Enforce validation",
- "type": "checkbox"
- },
- "showMessages": {
- "rightLabel":"Show validation messages",
- "type": "checkbox"
- },
- "disabled": {
- "rightLabel":"Disable this field",
- "type": "checkbox"
- },
- "hidden": {
- "type": "checkbox",
- "rightLabel": "Hide this field"
- },
- "label": {
- "type": "text"
- },
- "helper": {
- "type": "textarea"
- },
- "fieldClass": {
- "type": "text"
- },
- "hideInitValidationError": {
- "rightLabel": "Hide initial validation errors",
- "type": "checkbox"
- },
- "focus": {
- "type": "checkbox",
- "rightLabel": "Auto-focus first child field"
- },
- "optionLabels": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "view": {
- "type": "text"
- }
- }
- };
- if (this.isTopLevel()) {
- optionsForOptions.fields.form = {
- "type": "object",
- "fields": {
- "attributes": {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "action": {
- "type": "text"
- },
- "method": {
- "type": "select"
- },
- "name": {
- "type": "text"
- }
- }
- }
- }
- };
- }
-
- return optionsForOptions;
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "disallowValue": "{0} are disallowed values.",
- "notOptional": "This field is not optional."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ControlField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ControlField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a control field.
- */
- onConstruct: function()
- {
- var _this = this;
-
- this.isControlField = true;
-
- // helper method for getting val() from the control
- // handles conversion to the correct scalar type
- this._getControlVal = function(ensureProperType) {
- var val = null;
-
- if (this.control)
- {
- val = $(this.control).val();
-
- if (ensureProperType)
- {
- val = _this.ensureProperType(val);
- }
- }
-
- return val;
- };
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var controlTemplateType = self.resolveControlTemplateType();
- if (!controlTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for control: " + self.getFieldType());
- }
-
- this.controlDescriptor = this.view.getTemplateDescriptor("control-" + controlTemplateType, self);
- },
-
- getControlEl: function()
- {
- return this.control;
- },
-
- resolveControlTemplateType: function()
- {
- var self = this;
-
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("control-" + b.getFieldType(), self);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- onSetup: function()
- {
-
- },
-
- isAutoFocusable: function()
- {
- return true;
- },
-
- /**
- * For control fields, we use the "control" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "control";
- },
-
- /**
- * Add a "control" dom element inside of the field which houses our custom control.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.control = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTROL_FIELD);
- this.control.removeClass(Alpaca.MARKER_CLASS_CONTROL_FIELD);
-
- // render
- self.prepareControlModel(function(model) {
- self.beforeRenderControl(model, function() {
- self.renderControl(model, function(controlField) {
-
- if (controlField)
- {
- self.control.replaceWith(controlField);
- self.control = controlField;
-
- self.control.addClass(Alpaca.CLASS_CONTROL);
- }
-
- // CALLBACK: "control"
- self.fireCallback("control");
-
- self.afterRenderControl(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the control.
- *
- * @param callback function(model)
- */
- prepareControlModel: function(callback)
- {
- var self = this;
-
- var model = {};
- model.id = this.getId();
- model.name = this.name;
- model.options = this.options;
- model.schema = this.schema;
- model.data = this.data;
- model.required = this.isRequired();
- model.view = this.view;
-
- callback(model);
- },
-
- /**
- * Called before the control is rendered.
- *
- * @extension-point
- *
- * @param callback
- */
- beforeRenderControl: function(model, callback)
- {
- callback();
- },
-
- /**
- * Called after the control is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- if (!self.firstUpdateObservableFire)
- {
- if ((typeof(self.data) == "undefined") || self.data == null)
- {
- // do not handle
- }
- else
- {
- self.firstUpdateObservableFire = true;
- self.updateObservable();
- }
- }
-
- callback();
- },
-
- /**
- * Renders the control into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderControl: function(model, callback)
- {
- var control = null;
-
- if (this.controlDescriptor)
- {
- control = Alpaca.tmpl(this.controlDescriptor, model);
- }
-
- callback(control);
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- /*
- // store reference to the label
- this.labelDiv = $(this.field).find(".alpaca-controlfield-label");
- var labelDiv = $('.alpaca-controlfield-label', this.outerEl);
- if (labelDiv.length) {
- this.labelDiv = labelDiv;
- }
-
- var helperDiv = $('.alpaca-controlfield-helper', this.outerEl);
- if (helperDiv.length) {
- this.helperDiv = helperDiv;
- }
- */
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#setDefault
- */
- setDefault: function() {
- var defaultData = Alpaca.isEmpty(this.schema['default']) ? "" : this.schema['default'];
- this.setValue(defaultData);
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- if (this.schema["enum"]) {
- var val = this.data;
- val = this.getValue();
- /*this.getValue();*/
- if (!this.isRequired() && Alpaca.isValEmpty(val)) {
- return true;
- }
- if ($.inArray(val, this.schema["enum"]) > -1) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateEnum();
- valInfo["invalidValueOfEnum"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidValueOfEnum"), [this.schema["enum"].join(', '), this.data]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidValueOfEnum"]["status"];
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- this.initControlEvents();
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- var control = this.control;
-
- control.click(function(e) {
- self.onClick.call(self, e);
- self.trigger("click", e);
- });
-
- // trigger control level handlers for things that happen to input element
- control.change(function(e) {
-
- // we use a timeout here because we want this to run AFTER control click handlers
- setTimeout(function() {
- self.onChange.call(self, e);
- self.triggerWithPropagation("change", e);
- }, 250);
- });
-
- control.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- control.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
-
- control.keypress(function(e) {
- self.onKeyPress.call(self, e);
- self.trigger("keypress", e);
- });
-
- control.keyup(function(e) {
- self.onKeyUp.call(self, e);
- self.trigger("keyup", e);
- });
-
- control.keydown(function(e) {
- self.onKeyDown.call(self, e);
- self.trigger("keydown", e);
- });
- },
-
- /**
- * Callback for when a key press event is received for the field control.
- *
- * @param {Object} e keypress event
- */
- onKeyPress: function(e)
- {
- var self = this;
-
- // if the field is currently invalid, then we provide early feedback to the user as to when they enter
- // if the field was valid, we don't render invalidation feedback until they blur the field
-
- // was the control valid previously?
- var wasValid = this.isValid();
- if (!wasValid)
- {
- //
- // we use a timeout because at this exact moment, the value of the control is still the old value
- // jQuery raises the keypress event ahead of the input receiving the new data which would incorporate
- // the key that was pressed
- //
- // this timeout provides the browser with enough time to plug the value into the input control
- // which the validation logic uses to determine whether the control is now in a valid state
- //
- window.setTimeout(function() {
- self.refreshValidationState();
- }, 50);
- }
-
- },
-
- /**
- * Callback for when a key down event is received for the field control.
- *
- * @param {Object} e keydown event
- */
- onKeyDown: function(e)
- {
- },
-
- /**
- * Callback for when a key up event is received for the field control.
- *
- * @param {Object} e keyup event
- */
- onKeyUp: function(e)
- {
- },
-
- /**
- * Handler for click event.
- *
- * @param {Object} e Click event.
- */
- onClick: function(e)
- {
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", true);
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", false);
- }
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumerated Values",
- "description": "List of specific values for this property",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "enum": {
- "itemLabel":"Value",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "name": {
- "title": "Field Name",
- "description": "Field Name.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "name": {
- "type": "text"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "invalidValueOfEnum": "This field should have one of the values in {0}. Current value is: {1}"
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ContainerField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ContainerField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a container field.
- */
- onConstruct: function()
- {
- this.isContainerField = true;
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return true;
- },
-
- getContainerEl: function()
- {
- return this.container;
- },
-
- /**
- * For container fields, we use the "container" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "container";
- },
-
- resolveContainerTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType(), this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- resolveContainerItemTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType() + "-item", this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerTemplateType = self.resolveContainerTemplateType();
- if (!containerTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container: " + self.getFieldType());
- }
-
- this.containerDescriptor = this.view.getTemplateDescriptor("container-" + containerTemplateType, self);
-
- var collapsible = true;
-
- if (!Alpaca.isEmpty(this.view.collapsible)) {
- collapsible = this.view.collapsible;
- }
-
- if (!Alpaca.isEmpty(this.options.collapsible)) {
- collapsible = this.options.collapsible;
- }
-
- this.options.collapsible = collapsible;
-
- var legendStyle = "button";
-
- if (!Alpaca.isEmpty(this.view.legendStyle)) {
- legendStyle = this.view.legendStyle;
- }
-
- if (!Alpaca.isEmpty(this.options.legendStyle)) {
- legendStyle = this.options.legendStyle;
- }
-
- this.options.legendStyle = legendStyle;
-
- //Lazy loading
- this.lazyLoading = false;
- if (!Alpaca.isEmpty(this.options.lazyLoading)) {
- this.lazyLoading = this.options.lazyLoading;
- if (this.lazyLoading) {
- this.options.collapsed = true;
- }
- //delete this.options.lazyLoading;
- }
- // holders of references to children
- this.children = [];
- this.childrenById = {};
- this.childrenByPropertyId = {};
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // if this container is DOM-wrapped with a form, then release the form
- if (this.form)
- {
- this.form.destroy(true); // pass in true so that we don't call back recursively
- delete this.form;
- }
-
- // destroy any child controls
- Alpaca.each(this.children, function() {
- this.destroy();
- });
-
- // call up to base method
- this.base();
- },
-
- /**
- * Add a "container" dom element inside of the field which houses our custom container.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.container = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD);
- this.container.removeClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD);
-
- // render
- self.prepareContainerModel(function(model) {
- self.beforeRenderContainer(model, function() {
- self.renderContainer(model, function(containerField) {
-
- if (containerField)
- {
- self.container.replaceWith(containerField);
- self.container = containerField;
-
- self.container.addClass(Alpaca.CLASS_CONTAINER);
- }
-
- // mark the form field with "alpaca-horizontal" or "alpaca-vertical"
- if (self.view.horizontal)
- {
- self.container.addClass("alpaca-horizontal");
- }
- else
- {
- self.container.addClass("alpaca-vertical");
- }
-
- // CALLBACK: "container"
- self.fireCallback("container");
-
- self.afterRenderContainer(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the container.
- *
- * @param callback function(model)
- */
- prepareContainerModel: function(callback)
- {
- var self = this;
-
- var model = {
- "id": this.getId(),
- "name": this.name,
- "schema": this.schema,
- "options": this.options,
- "view": this.view
- };
-
- // load items into array and store on model for future use
- self.createItems(function(items) {
-
- if (!items)
- {
- items = [];
- }
-
- // legacy support: assume containerItemEl = fieldEl
- for (var i = 0; i < items.length; i++)
- {
- if (!items[i].containerItemEl) {
- items[i].containerItemEl = items[i].getFieldEl();
- }
- }
-
- model.items = items;
-
- callback(model);
-
- });
- },
-
- /**
- * Called before the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- beforeRenderContainer: function(model, callback)
- {
- var self = this;
-
- callback();
- },
-
- /**
- * Renders the container into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderContainer: function(model, callback)
- {
- var container = null;
-
- if (this.containerDescriptor)
- {
- container = Alpaca.tmpl(this.containerDescriptor, model);
- }
-
- callback(container);
- },
-
- /**
- * Called after the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- self.beforeApplyCreatedItems(model, function() {
- self.applyCreatedItems(model, function () {
- self.afterApplyCreatedItems(model, function () {
- callback();
- });
- });
- });
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- var self = this;
-
- this.base();
-
- /*
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
- */
- },
-
- /**
- * Creates any sub-items for this container.
- *
- * @extension_point
- *
- * @param callback
- */
- createItems: function(callback)
- {
- callback();
- },
-
- beforeApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.isTopLevel() && self.view.getLayout())
- {
- layoutBindings = self.view.getLayout().bindings;
-
- // if layout and bindings not provided, assume a default strategy
- if (!layoutBindings && self.view.getLayout().templateDescriptor && model.items.length > 0)
- {
- layoutBindings = {};
-
- for (var i = 0; i < model.items.length; i++)
- {
- var name = model.items[i].name;
-
- layoutBindings[name] = "[data-alpaca-layout-binding='" + name + "']";
- }
- }
-
- }
-
- if (model.items.length > 0)
- {
- $(self.container).addClass("alpaca-container-has-items");
- $(self.container).attr("data-alpaca-container-item-count", model.items.length);
- }
- else
- {
- $(self.container).removeClass("alpaca-container-has-items");
- $(self.container).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < model.items.length; i++)
- {
- var item = model.items[i];
-
- // find the insertion point
- var insertionPoint = $(self.container).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM + "[" + Alpaca.MARKER_DATA_CONTAINER_FIELD_ITEM_KEY + "='" + item.name + "']");
- if (!layoutBindings)
- {
- var holder = $(insertionPoint).parent();
-
- $(insertionPoint).replaceWith(item.containerItemEl);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- else
- {
- // use a layout
- var bindingId = layoutBindings[item.name];
- if (bindingId)
- {
- var holder = $(bindingId, self.field);
- if (holder.length == 0)
- {
- // legacy support, fallback to ID based
- try {
- holder = $('#' + bindingId, self.field);
- } catch (e) { }
- }
- if (holder.length > 0)
- {
- $(item.containerItemEl).appendTo(holder);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- }
-
- // remove insertion point
- $(insertionPoint).remove();
- }
-
- $(item.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-first");
- }
-
- if (i + 1 === model.items.length)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(item.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(item.containerItemEl).attr("data-alpaca-container-item-name", item.name);
- $(item.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
-
- // register the child
- self.registerChild(item, i);
- }
-
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
-
- self.triggerUpdate();
- callback();
- },
-
- afterApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- /**
- * Helper method to add child field.
- *
- * @param {Alpaca.Control} child Child field to be added.
- * @param {Integer} index Index of the new child.
- */
- registerChild: function(child, index)
- {
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 0, child);
- }
- else
- {
- this.children.push(child);
- }
-
- this.childrenById[child.getId()] = child;
- if (child.propertyId)
- {
- this.childrenByPropertyId[child.propertyId] = child;
- }
-
- child.parent = this;
- },
-
- /**
- * Helper method to remove child field.
- *
- * @param index
- */
- unregisterChild: function(index)
- {
- var child = this.children[index];
- if (!child)
- {
- return;
- }
-
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 1);
- }
-
- delete this.childrenById[child.getId()];
- if (child.propertyId)
- {
- delete this.childrenByPropertyId[child.propertyId];
- }
-
- child.parent = null;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updateChildDOMElements: function()
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.view.getLayout()) {
- layoutBindings = self.view.getLayout().bindings;
- }
-
- if (!layoutBindings)
- {
- if (self.children.length > 0)
- {
- $(self.getContainerEl()).addClass("alpaca-container-has-items");
- $(self.getContainerEl()).attr("data-alpaca-container-item-count", self.children.length);
- }
- else
- {
- $(self.getContainerEl()).removeClass("alpaca-container-has-items");
- $(self.getContainerEl()).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < self.children.length; i++)
- {
- var child = self.children[i];
-
- // reset path and name
- child.path = self.path + "[" + i + "]";
- child.calculateName();
-
- $(child.containerItemEl).removeClass("alpaca-container-item-first");
- $(child.containerItemEl).removeClass("alpaca-container-item-last");
- $(child.containerItemEl).removeClass("alpaca-container-item-index");
- $(child.containerItemEl).removeClass("alpaca-container-item-key");
-
- $(child.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-first");
- }
- if (i + 1 === self.children.length)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(child.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(child.containerItemEl).attr("data-alpaca-container-item-name", child.name);
- $(child.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
- }
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentReveal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentReveal();
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentConceal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentConceal();
- }
- },
-
- /**
- * Focus an element in the container. Find the first invalid element or if no invalid elements, pick
- * the first child.
- */
- focus: function()
- {
- this.base();
-
- var index = -1;
-
- for (var i = 0; i < this.children.length; i++)
- {
- if (!this.children[i].isValid(true))
- {
- index = i;
- break;
- }
- }
- if (index === -1 && this.children.length > 0)
- {
- index = 0;
- }
-
- if (index > -1)
- {
- this.children[index].focus();
- }
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].disable();
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].enable();
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "lazyLoading": {
- "title": "Lazy Loading",
- "description": "Child fields will only be rendered when the fieldset is expanded if this option is set true.",
- "type": "boolean",
- "default": false
- },
- "collapsible": {
- "title": "Collapsible",
- "description": "Field set is collapsible if true.",
- "type": "boolean",
- "default": true
- },
- "collapsed": {
- "title": "Collapsed",
- "description": "Field set is initially collapsed if true.",
- "type": "boolean",
- "default": false
- },
- "legendStyle": {
- "title": "Legend Style",
- "description": "Field set legend style.",
- "type": "string",
- "enum":["button","link"],
- "default": "button"
- },
- "animate": {
- "title": "Animate movements and transitions",
- "description": "Up and down transitions will be animated",
- "type": "boolean",
- "default": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "lazyLoading": {
- "rightLabel": "Lazy loading child fields ?",
- "helper": "Lazy loading will be enabled if checked.",
- "type": "checkbox"
- },
- "collapsible": {
- "rightLabel": "Field set collapsible ?",
- "helper": "Field set is collapsible if checked.",
- "type": "checkbox"
- },
- "collapsed": {
- "rightLabel": "Field set initially collapsed ?",
- "description": "Field set is initially collapsed if checked.",
- "type": "checkbox"
- },
- "legendStyle": {
- "type":"select"
- },
- "animate": {
- "rightLabel": "Animate movements and transitions",
- "type": "checkbox"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Connector = Base.extend(
- /**
- * @lends Alpaca.Connector.prototype
- */
- {
- /**
- * @constructs
- * @class Connects Alpaca to remote data stores.
-
- * @param {String} id Connector ID.
- */
- constructor: function(id)
- {
- this.id = id;
-
- // helper function to determine if a resource is a uri
- this.isUri = function(resource)
- {
- return !Alpaca.isEmpty(resource) && Alpaca.isUri(resource);
- };
-
- var ONE_HOUR = 3600000;
- this.cache = new AjaxCache('URL', true, ONE_HOUR);
- },
-
- /**
- * Makes initial connections to data source.
- *
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- connect: function (onSuccess, onError)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess();
- }
- },
-
- /**
- * Loads a template (HTML or Text).
- *
- * If the source is a URI, then it is loaded.
- * If it is not a URI, then the source is simply handed back.
- *
- * @param {Object|String} source Source to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadTemplate : function (source, onSuccess, onError)
- {
- if (!Alpaca.isEmpty(source))
- {
- if (Alpaca.isUri(source))
- {
- this.loadUri(source, false, function(loadedData) {
-
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loadedData);
- }
-
- }, function (loadError) {
-
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- });
- }
- else
- {
- onSuccess(source);
- }
- }
- else
- {
- onError({
- "message":"Empty data source.",
- "reason": "TEMPLATE_LOADING_ERROR"
- });
- }
- },
-
- /**
- * Loads JSON data.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback
- * @param {Function} onError onError callback
- */
- loadData: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON view.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadView: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads schema, form, view and data in a single call.
- *
- * @param {Object} resources resources
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadAll: function (resources, onSuccess, onError)
- {
- var dataSource = resources.dataSource;
- var schemaSource = resources.schemaSource;
- var optionsSource = resources.optionsSource;
- var viewSource = resources.viewSource;
-
- // we allow "schema" to contain a URI as well (backwards-compatibility)
- if (!schemaSource)
- {
- schemaSource = resources.schema;
- }
-
- // we allow "options" to contain a URI as well (backwards-compatibility)
- if (!optionsSource)
- {
- optionsSource = resources.options;
- }
-
- // we allow "view" to contain a URI as well (backwards-compatibility)
- if (!viewSource)
- {
- viewSource = resources.view;
- }
-
- var loaded = {};
-
- var loadCounter = 0;
- var invocationCount = 0;
-
- var successCallback = function()
- {
- if (loadCounter === invocationCount)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loaded.data, loaded.options, loaded.schema, loaded.view);
- }
- }
- };
-
- var errorCallback = function (loadError)
- {
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- };
-
- // count out the total # of invokes we're going to fire off
- if (dataSource)
- {
- invocationCount++;
- }
- if (schemaSource)
- {
- invocationCount++;
- }
- if (optionsSource)
- {
- invocationCount++;
- }
- if (viewSource)
- {
- invocationCount++;
- }
- if (invocationCount === 0)
- {
- // nothing to invoke, so just hand back
- successCallback();
- return;
- }
-
- // fire off all of the invokes
- if (dataSource)
- {
- this.loadData(dataSource, function(data) {
- loaded.data = data;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (schemaSource)
- {
- this.loadSchema(schemaSource, function(schema) {
- loaded.schema = schema;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (optionsSource)
- {
- this.loadOptions(optionsSource, function(options) {
- loaded.options = options;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (viewSource)
- {
- this.loadView(viewSource, function(view) {
- loaded.view = view;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- },
-
- /**
- * Loads a JSON through Ajax call.
- *
- * @param {String} uri location of the json document
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadJson : function(uri, onSuccess, onError) {
- this.loadUri(uri, true, onSuccess, onError);
- } ,
-
- /**
- * Loads a general document through Ajax call.
- *
- * This uses jQuery to perform the Ajax call. If you need to customize connectivity to your own remote server,
- * this would be the appropriate place to do so.
- *
- * @param {String} uri uri to be loaded
- * @param {Boolean} isJson Whether the document is a JSON or not.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadUri : function(uri, isJson, onSuccess, onError) {
-
- var self = this;
-
- var ajaxConfigs = {
- "url": uri,
- "type": "get",
- "success": function(jsonDocument) {
-
- self.cache.put(uri, jsonDocument);
-
- if (onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(jsonDocument);
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
- if (onError && Alpaca.isFunction(onError)) {
- onError({
- "message":"Unable to load data from uri : " + uri,
- "stage": "DATA_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- }
- };
-
- if (isJson) {
- ajaxConfigs.dataType = "json";
- } else {
- ajaxConfigs.dataType = "text";
- }
-
- var cachedDocument = self.cache.get(uri);
-
- if (cachedDocument !== false && onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(cachedDocument);
- } else {
- $.ajax(ajaxConfigs);
- }
- },
-
- /**
- * Loads referenced JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads referenced JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- _handleLoadJsonResource: function (resource, successCallback, errorCallback)
- {
- if (this.isUri(resource))
- {
- this.loadJson(resource, function(loadedResource) {
- successCallback(loadedResource);
- }, errorCallback);
- }
- else
- {
- successCallback(resource);
- }
- }
-
- });
-
- Alpaca.registerConnectorClass("default", Alpaca.Connector);
-
-
-
-
-
-
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // AJAX CACHE
- //
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
- /*!
- * ajax-cache JavaScript Library v0.2.1
- * http://code.google.com/p/ajax-cache/
- *
- * Includes few JSON methods (open source)
- * http://www.json.org/js.html
- *
- * Date: 2010-08-03
- */
- var AjaxCache = function AjaxCache(type, on, lifetime) {
- if (on) {
- this.on = true;
- } else {
- this.on = false;
- }
-
- // set default cache lifetime
- if (lifetime != null) {
- this.defaultLifetime = lifetime;
- }
-
- // set type
- this.type = type;
-
- // set cache functions according to type
- switch (this.type) {
- case 'URL':
- this.put = this.put_url;
- break;
- case 'GET':
- this.put = this.put_GET;
- break;
- }
-
- };
-
- AjaxCache.prototype.on = false;
- AjaxCache.prototype.type = undefined;
- AjaxCache.prototype.defaultLifetime = 1800000; // 1800000=30min, 300000=5min, 30000=30sec
- AjaxCache.prototype.items = {};
-
- /**
- * Caches the request and its response. Type: url
- *
- * @param url - url of ajax response
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_url = function(url, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Caches the request and its response. Type: GET
- *
- * @param url - url of ajax response
- * @param data - data params (query)
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_GET = function(url, data, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url, [ data ]);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].data = data;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Get cached ajax response
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return ajax response or false if such does not exist or is expired
- */
- AjaxCache.prototype.get = function(url, params) {
- var key = this.make_key(url, params);
-
- // if cache does not exist
- if (this.items[key] == null) {
- return false;
- }
-
- // if cache expired
- if (this.items[key].expire < (new Date().getTime())) {
- return false;
- }
-
- // everything is passed - lets return the response
- return this.items[key].response;
- };
-
- /**
- * Make unique key for each request depending on url and additional parameters
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return unique key
- */
- AjaxCache.prototype.make_key = function(url, params) {
- var key = url;
- switch (this.type) {
- case 'URL':
- break;
- case 'GET':
- key += this.stringify(params[0]);
- break;
- }
-
- return key;
- };
-
- /**
- * Flush cache
- *
- * @return true on success
- */
- AjaxCache.prototype.flush = function() {
- // flush all cache
- cache.items = {};
- return true;
- };
-
- /*
- * Methods to stringify JavaScript/JSON objects.
- *
- * Taken from: http://www.json.org/js.html to be more exact, this file:
- * http://www.json.org/json2.js copied on 2010-07-19
- *
- * Taken methods: stringify, quote and str
- *
- * Methods are slightly modified to best fit ajax-cache functionality
- *
- */
- AjaxCache.prototype.stringify = function(value, replacer, space) {
-
- // The stringify method takes a value and an optional replacer, and an
- // optional
- // space parameter, and returns a JSON text. The replacer can be a function
- // that can replace values, or an array of strings that will select the
- // keys.
- // A default replacer method can be provided. Use of the space parameter can
- // produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
- // If the space parameter is a number, make an indent string containing that
- // many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
- // If the space parameter is a string, it will be used as the indent
- // string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
- // If there is a replacer, it must be a function or an array.
- // Otherwise, throw an error.
-
- rep = replacer;
- if (replacer &&
- typeof replacer !== 'function' &&
- (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
- // Make a fake root object containing our value under the key of ''.
- // Return the result of stringifying the value.
-
- return this.str('', {
- '' : value
- });
- };
-
- AjaxCache.prototype.quote = function(string) {
-
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe escape
- // sequences.
-
- var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable,
- function(a) {
- var c = meta[a];
- return typeof c === 'string' ? c : '\\u' + ('0000' + a
- .charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- };
-
- AjaxCache.prototype.str = function(key, holder) {
-
- // Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length, mind = gap, partial, value = holder[key];
-
- // If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value &&
- typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
- // If we were called with a replacer function, then call the replacer to
- // obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
- // What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return this.quote(value);
-
- case 'number':
-
- // JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
- // If the value is a boolean or null, convert it to a string. Note:
- // typeof null does not produce 'null'. The case is included here in
- // the remote chance that this gets fixed someday.
-
- return String(value);
-
- // If the type is 'object', we might be dealing with an object or an
- // array or
- // null.
-
- case 'object':
-
- // Due to a specification blunder in ECMAScript, typeof null is
- // 'object',
- // so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
- // Make an array to hold the partial results of stringifying this object
- // value.
-
- gap += indent;
- partial = [];
-
- // Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
- // The value is an array. Stringify every element. Use null as a
- // placeholder
- // for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = this.str(i, value) || 'null';
- }
-
- // Join all of the elements together, separated with commas, and
- // wrap them in
- // brackets.
-
- v = partial.length === 0 ? '[]' : gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
- // If the replacer is an array, use it to select the members to be
- // stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
- // Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
- // Join all of the member texts together, separated with commas,
- // and wrap them in braces.
-
- v = partial.length === 0 ?
- '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- };
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Form = Base.extend(
- /**
- * @lends Alpaca.Form.prototype
- */
- {
- /**
- * @constructs
- *
- * @class This class is for managing HTML form control.
- *
- * @param {Object} container Field container.
- * @param {Object} options Field options.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(domEl, options, viewId, connector, errorCallback) {
-
- // container
- this.domEl = domEl;
-
- // parent
- this.parent = null;
-
- this.connector = connector;
- this.errorCallback = errorCallback;
-
- // options
- this.options = options;
-
- if (this.options.attributes)
- {
- this.attributes = this.options.attributes;
- }
- else
- {
- this.attributes = {};
- }
-
- if (this.options.buttons)
- {
- if (this.options.buttons.submit)
- {
- if (!this.options.buttons.submit.type)
- {
- this.options.buttons.submit.type = 'submit';
- }
-
- if (!this.options.buttons.submit.name)
- {
- this.options.buttons.submit.name = 'submit';
- }
-
- if (!this.options.buttons.submit.value)
- {
- this.options.buttons.submit.value = 'Submit';
- }
- }
-
- if (this.options.buttons.reset)
- {
- if (!this.options.buttons.reset.type)
- {
- this.options.buttons.reset.type = 'reset';
- }
- if (!this.options.buttons.reset.name)
- {
- this.options.buttons.reset.name = 'reset';
- }
- if (!this.options.buttons.reset.value)
- {
- this.options.buttons.reset.value = 'Reset';
- }
- }
-
- // some general correction
- for (var k in this.options.buttons)
- {
- if (this.options.buttons[k].label)
- {
- this.options.buttons[k].value = this.options.buttons[k].label;
- }
- if (this.options.buttons[k].title)
- {
- this.options.buttons[k].value = this.options.buttons[k].title;
- }
- if (!this.options.buttons[k].type)
- {
- this.options.buttons[k].type = "button";
- }
- }
- }
-
- if (this.attributes.id)
- {
- this.id = this.attributes.id;
- }
- else
- {
- this.id = Alpaca.generateId();
- this.attributes.id = this.id;
- }
-
- // if we have a submit button specified, and toggleSubmitValidState isn't defined, set to true by default
- // don't allow the form to submit unless valid
- if (this.options.buttons && this.options.buttons.submit && Alpaca.isUndefined(this.options.toggleSubmitValidState))
- {
- this.options.toggleSubmitValidState = true;
- }
-
- this.viewType = options.viewType;
-
- // set a runtime view
- this.view = new Alpaca.RuntimeView(viewId, this);
- },
-
- /**
- * Renders this form into the container.
- *
- * @param {Function} callback
- */
- render: function(callback)
- {
- var self = this;
-
- // remove the previous form element if it exists
- if (this.form)
- {
- this.form.remove();
- }
-
- // load the appropriate template and render it
- this.processRender(this.domEl, function() {
-
- // bind our field dom element into the container
- self.form.appendTo(self.container);
-
- // add default class
- self.form.addClass("alpaca-form");
-
- // CALLBACK: "form"
- self.fireCallback("form");
-
- // execute callback
- callback(self);
- });
- },
-
- /**
- * Determines whether the top control is entirely valid.
- *
- * @return {*}
- */
- isFormValid: function()
- {
- // re-compute validation for the full control set
- this.topControl.validate(true);
-
- var valid = this.topControl.isValid(true);
- //this.refreshValidationState(true);
-
- return valid;
- },
-
- isValid: function()
- {
- return this.isFormValid();
- },
-
- validate: function(children)
- {
- return this.topControl.validate(children);
- },
-
- enableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", false);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- disableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", true);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- adjustSubmitButtonState: function()
- {
- this.disableSubmitButton();
-
- if (this.isFormValid())
- {
- this.enableSubmitButton();
- }
- },
-
- /**
- * Responsible for fetching any templates needed so as to render the
- * current mode for this field.
- *
- * Once completed, the onSuccess method is called.
- *
- * @param {Object} parentEl Field container.
- * @param {Function} callback
- */
- processRender: function(parentEl, callback)
- {
- var self = this;
-
- // lookup the template we should use to render
- this.formDescriptor = this.view.getTemplateDescriptor("form");
- if (!this.formDescriptor)
- {
- return Alpaca.throwErrorWithCallback("Could not find template descriptor: form");
- }
-
- var renderedDomElement = Alpaca.tmpl(this.formDescriptor, {
- id: this.getId(),
- options: this.options,
- view: this.view
- });
- renderedDomElement.appendTo(parentEl);
-
- this.form = renderedDomElement;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.formFieldsContainer = $(this.form).find("." + Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
- this.formFieldsContainer.removeClass(Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
-
- if (Alpaca.isEmpty(this.form.attr("id")))
- {
- this.form.attr("id", this.getId() + "-form-outer");
- }
- if (Alpaca.isEmpty(this.form.attr("data-alpaca-form-id")))
- {
- this.form.attr("data-alpaca-form-id", this.getId());
- }
-
- // the form field
- parentEl.find("form").attr(this.attributes);
-
- // populate the buttons as well
- this.buttons = {};
- $(parentEl).find(".alpaca-form-button").each(function() {
-
- $(this).click(function(e) {
- $(this).attr("button-pushed", true);
- });
-
- // custom click handler?
- var key = $(this).attr("data-key");
- if (key)
- {
- var buttonConfig = self.options.buttons[key];
- if (buttonConfig)
- {
- if (buttonConfig.click)
- {
- $(this).click(function(form, handler) {
- return function(e) {
- e.preventDefault();
- handler.call(form, e);
- }
- }(self, buttonConfig.click));
- }
- }
- }
- });
-
- callback();
- },
-
- /**
- * Returns the id of the form.
- *
- * @returns {String} Form id
- */
- getId: function()
- {
- return this.id;
- },
-
- /**
- * Returns form type.
- *
- * @returns {String} Form type.
- */
- getType: function()
- {
- return this.type;
- },
-
- /**
- * Returns this form's parent.
- *
- * @returns {Object} Form parent.
- */
- getParent: function()
- {
- return this.parent;
- },
-
- /**
- * Returns the value of the JSON rendered by this form.
- *
- * @returns {Any} Value of the JSON rendered by this form.
- */
- getValue: function()
- {
- return this.topControl.getValue();
- },
-
- /**
- * Sets the value of the JSON to be rendered by this form.
- *
- * @param {Any} value Value to be set.
- */
- setValue: function(value)
- {
- this.topControl.setValue(value);
- },
-
- /**
- * Initializes events handling (Form Submission) for this form.
- */
- initEvents: function()
- {
- var _this = this;
-
- var formTag = $(this.domEl).find("form");
-
- var v = this.getValue();
- $(formTag).submit(v, function(e) {
- return _this.onSubmit(e, _this);
- });
-
- // listen for fieldupdates and determine whether the form is valid.
- // if so, enable the submit button...
- // otherwise, disable it
- if (this.options.toggleSubmitValidState)
- {
- $(_this.topControl.getFieldEl()).bind("fieldupdate", function() {
- _this.adjustSubmitButtonState();
- });
-
- this.adjustSubmitButtonState();
- }
- },
-
- getButtonEl: function(buttonId)
- {
- return $(this.domEl).find(".alpaca-form-button-" + buttonId);
- },
-
- /**
- * Handles form submit events.
- *
- * @param {Object} e Submit event.
- * @param {Object} form the form
- */
- onSubmit: function(e, form)
- {
- if (this.submitHandler)
- {
- e.stopPropagation();
-
- var v = this.submitHandler(e, form);
- if (Alpaca.isUndefined(v)) {
- v = false;
- }
-
- return v;
- }
- },
-
- /**
- * Registers a custom submit handler.
- *
- * @param {Object} func Submit handler to be registered.
- */
- registerSubmitHandler: function (func)
- {
- if (Alpaca.isFunction(func))
- {
- this.submitHandler = func;
- }
- },
-
- /**
- * Displays validation information of all fields of this form.
- *
- * @param {Boolean} children whether to render validation state for child fields
- *
- * @returns {Object} Form validation state.
- */
- refreshValidationState: function(children, callback)
- {
- this.topControl.refreshValidationState(children, callback);
- },
-
- /**
- * Disables this form.
- */
- disable: function()
- {
- this.topControl.disable();
- },
-
- /**
- * Enables this form.
- */
- enable: function()
- {
- this.topControl.enable();
- },
-
- /**
- * Focuses on this form.
- */
- focus: function()
- {
- this.topControl.focus();
- },
-
- /**
- * Purge any event listeners and remove the form from the DOM.
- *
- * @param [Boolean] skipParent when true, the form cleans up without traversing through parent child controls
- */
- destroy: function(skipParent)
- {
- this.getFormEl().remove();
-
- // we allow form.destroy() which tells parent control to destroy
- // if skipParent == true, then we do not call up (invoked from container)
- if (!skipParent && this.parent)
- {
- this.parent.destroy();
- }
- },
-
- /**
- * Shows the form.
- */
- show: function()
- {
- this.getFormEl().css({
- "display": ""
- });
- },
-
- /**
- * Hides the form.
- */
- hide: function()
- {
- this.getFormEl().css({
- "display": "none"
- });
- },
-
- /**
- * Clears the form and resets values of its fields.
- *
- * @param stopUpdateTrigger If false, triggers the update event of this event.
- */
- clear: function(stopUpdateTrigger)
- {
- this.topControl.clear(stopUpdateTrigger);
- },
-
- /**
- * Checks if form is empty.
- *
- * @returns {Boolean} True if the form is empty, false otherwise.
- */
- isEmpty: function()
- {
- return this.topControl.isEmpty();
- },
-
- /**
- * Fires a view callback for the current form.
- *
- * @param id
- * @param arg1
- * @param arg2
- * @param arg3
- * @param arg4
- * @param arg5
- */
- fireCallback: function(id, arg1, arg2, arg3, arg4, arg5)
- {
- this.view.fireCallback(this, id, arg1, arg2, arg3, arg4, arg5);
- },
-
- /**
- * Retrieves the form element.
- *
- * @returns {Object} The rendered DOM element.
- */
- getFormEl: function() {
- return this.form;
- },
-
- /**
- * Performs a regular old submit.
- */
- submit: function()
- {
- this.form.submit();
- },
-
- /**
- * Fires the submit in the background and hands back the jQuery promise.
- *
- * @returns {*}
- */
- ajaxSubmit: function()
- {
- var self = this;
-
- return $.ajax({
- data: this.getValue(),
- url: self.options.attributes.action,
- type: self.options.attributes.method,
- dataType: "json"
- });
- }
-
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.TextField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "text";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
-
- /*
- if (!this.options.size) {
- this.options.size = 40;
- }
- */
-
- // assume html5 input type = "text"
- if (!this.inputType)
- {
- this.inputType = "text";
- }
-
- if (this.options.inputType)
- {
- this.inputType = this.options.inputType;
- }
-
- // DOM data-* attributes support
- if (!this.options.data)
- {
- this.options.data = {};
- }
-
- // DOM * attributes support
- if (!this.options.attributes)
- {
- this.options.attributes = {};
- }
-
- if (typeof(this.options.allowOptionalEmpty) == "undefined")
- {
- this.options.allowOptionalEmpty = true;
- }
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- this.base();
-
- // clean up typeahead
- if ( this.control && this.control.typeahead && this.options.typeahead)
- {
- $(this.control).typeahead('destroy');
- }
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- if (self.control)
- {
- // mask
- self.applyMask();
-
- // typeahead
- self.applyTypeAhead();
-
- // update max length indicator
- self.updateMaxLengthIndicator();
- }
-
- callback();
- });
- },
-
- applyMask: function()
- {
- var self = this;
-
- // mask it
- if (self.control.mask && self.options.maskString)
- {
- self.control.mask(self.options.maskString);
- }
- },
-
- applyTypeAhead: function()
- {
- var self = this;
-
- if (self.control.typeahead && self.options.typeahead && !Alpaca.isEmpty(self.options.typeahead))
- {
- var tConfig = self.options.typeahead.config;
- if (!tConfig) {
- tConfig = {};
- }
-
- var tDatasets = self.options.typeahead.datasets;
- if (!tDatasets) {
- tDatasets = {};
- }
-
- if (!tDatasets.name) {
- tDatasets.name = self.getId();
- }
-
- var tEvents = self.options.typeahead.events;
- if (!tEvents) {
- tEvents = {};
- }
-
- // support for each datasets (local, remote, prefetch)
- if (tDatasets.type === "local" || tDatasets.type === "remote" || tDatasets.type === "prefetch")
- {
- var bloodHoundConfig = {
- datumTokenizer: function(d) {
- return Bloodhound.tokenizers.whitespace(d.value);
- },
- queryTokenizer: Bloodhound.tokenizers.whitespace
- };
-
- if (tDatasets.type === "local" )
- {
- var local = [];
-
- if (typeof(tDatasets.source) === "function")
- {
- bloodHoundConfig.local = tDatasets.source;
- }
- else
- {
- // array
- for (var i = 0; i < tDatasets.source.length; i++)
- {
- var localElement = tDatasets.source[i];
- if (typeof(localElement) === "string")
- {
- localElement = {
- "value": localElement
- };
- }
-
- local.push(localElement);
- }
-
- bloodHoundConfig.local = local;
- }
-
- if (tDatasets.local)
- {
- bloodHoundConfig.local = tDatasets.local;
- }
- }
-
- if (tDatasets.type === "prefetch")
- {
- bloodHoundConfig.prefetch = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.prefetch.filter = tDatasets.filter;
- }
- }
-
- if (tDatasets.type === "remote")
- {
- bloodHoundConfig.remote = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.remote.filter = tDatasets.filter;
- }
-
- if (tDatasets.replace)
- {
- bloodHoundConfig.remote.replace = tDatasets.replace;
- }
- }
-
- var engine = new Bloodhound(bloodHoundConfig);
- engine.initialize();
- tDatasets.source = engine.ttAdapter();
- }
-
- // compile templates
- if (tDatasets.templates)
- {
- for (var k in tDatasets.templates)
- {
- var template = tDatasets.templates[k];
- if (typeof(template) === "string")
- {
- tDatasets.templates[k] = Handlebars.compile(template);
- }
- }
- }
-
- // process typeahead
- $(self.control).typeahead(tConfig, tDatasets);
-
- // listen for "autocompleted" event and set the value of the field
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // listen for "selected" event and set the value of the field
- $(self.control).on("typeahead:selected", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // custom events
- if (tEvents)
- {
- if (tEvents.autocompleted) {
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- tEvents.autocompleted(event, datum);
- });
- }
- if (tEvents.selected) {
- $(self.control).on("typeahead:selected", function(event, datum) {
- tEvents.selected(event, datum);
- });
- }
- }
-
- // when the input value changes, change the query in typeahead
- // this is to keep the typeahead control sync'd with the actual dom value
- // only do this if the query doesn't already match
- var fi = $(self.control);
- $(self.control).change(function() {
-
- var value = $(this).val();
-
- var newValue = $(fi).typeahead('val');
- if (newValue !== value)
- {
- $(fi).typeahead('val', newValue);
- }
-
- });
-
- // some UI cleanup (we don't want typeahead to restyle)
- $(self.field).find("span.twitter-typeahead").first().css("display", "block"); // SPAN to behave more like DIV, next line
- $(self.field).find("span.twitter-typeahead input.tt-input").first().css("background-color", "");
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.inputType = self.inputType;
-
- callback(model);
- });
- },
-
- updateMaxLengthIndicator: function()
- {
- var self = this;
-
- var errState = false;
-
- var message = "";
- if (!Alpaca.isEmpty(self.schema.maxLength) && self.options.showMaxLengthIndicator)
- {
- var val = self.getValue() || "";
-
- var diff = self.schema.maxLength - val.length;
- if (diff >= 0)
- {
- message = "You have " + diff + " characters remaining";
- }
- else
- {
- message = "Your message is too long by " + (diff*-1) + " characters";
- errState = true;
- }
-
- var indicator = $(self.field).find(".alpaca-field-text-max-length-indicator");
- if (indicator.length === 0)
- {
- indicator = $("");
- $(self.control).after(indicator);
- }
-
- $(indicator).html(message);
- $(indicator).removeClass("err");
- if (errState)
- {
- $(indicator).addClass("err");
- }
- }
-
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!this.isDisplayOnly() && this.control && this.control.length > 0)
- {
- value = this._getControlVal(true);
-
- if (self.control.mask && self.options.maskString)
- {
- // get unmasked value
- var fn = $(this.control).data($.mask.dataName);
- if (fn)
- {
- value = fn();
- value = self.ensureProperType(value);
- }
- }
- }
- else
- {
- value = this.base();
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (this.control && this.control.length > 0)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
- }
-
- // be sure to call into base method
- this.base(value);
-
- // if applicable, update the max length indicator
- this.updateMaxLengthIndicator();
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validatePattern();
- valInfo["invalidPattern"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidPattern"), [this.schema.pattern]),
- "status": status
- };
-
- status = this._validateMaxLength();
- valInfo["stringTooLong"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooLong"), [this.schema.maxLength]),
- "status": status
- };
-
- status = this._validateMinLength();
- valInfo["stringTooShort"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooShort"), [this.schema.minLength]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidPattern"]["status"] && valInfo["stringTooLong"]["status"] && valInfo["stringTooShort"]["status"];
- },
-
- /**
- * Validates against the schema pattern property.
- *
- * @returns {Boolean} True if it matches the pattern, false otherwise.
- */
- _validatePattern: function()
- {
- if (this.schema.pattern)
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (!val.match(this.schema.pattern))
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates against the schema minLength property.
- *
- * @returns {Boolean} True if its size is greater than minLength, false otherwise.
- */
- _validateMinLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.minLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length < this.schema.minLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates against the schema maxLength property.
- *
- * @returns {Boolean} True if its size is less than maxLength , false otherwise.
- */
- _validateMaxLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.maxLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length > this.schema.maxLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- if (this.control && this.control.length > 0)
- {
- // focuses the control and also positions the input at the end
-
- var el = $(this.control).get(0);
-
- try {
- var elemLen = el.value ? el.value.length : 0;
- el.selectionStart = elemLen;
- el.selectionEnd = elemLen;
- }
- catch (e) {
- // field type doesn't support selection start and end
- }
-
- el.focus();
- }
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyDown: function(e)
- {
- var self = this;
-
- if (e.keyCode === 8) // backspace
- {
- if (!Alpaca.isEmpty(self.schema.minLength) && (self.options.constrainLengths || self.options.constrainMinLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length <= self.schema.minLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- else
- {
- if (!Alpaca.isEmpty(self.schema.maxLength) && (self.options.constrainLengths || self.options.constrainMaxLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length >= self.schema.maxLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- },
-
- onKeyUp: function(e)
- {
- var self = this;
-
- // if applicable, update the max length indicator
- self.updateMaxLengthIndicator();
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Single-Line Text";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Text field for single-line text.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minLength": {
- "title": "Minimal Length",
- "description": "Minimal length of the property value.",
- "type": "number"
- },
- "maxLength": {
- "title": "Maximum Length",
- "description": "Maximum length of the property value.",
- "type": "number"
- },
- "pattern": {
- "title": "Pattern",
- "description": "Regular expression for the property value.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "default": {
- "helper": "Field default value",
- "type": "text"
- },
- "minLength": {
- "type": "integer"
- },
- "maxLength": {
- "type": "integer"
- },
- "pattern": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "size": {
- "title": "Field Size",
- "description": "Field size.",
- "type": "number",
- "default":40
- },
- "maskString": {
- "title": "Mask Expression",
- "description": "Expression for the field mask. Field masking will be enabled if not empty.",
- "type": "string"
- },
- "placeholder": {
- "title": "Field Placeholder",
- "description": "Field placeholder.",
- "type": "string"
- },
- "typeahead": {
- "title": "Type Ahead",
- "description": "Provides configuration for the $.typeahead plugin if it is available. For full configuration options, see: https://github.com/twitter/typeahead.js"
- },
- "allowOptionalEmpty": {
- "title": "Allow Optional Empty",
- "description": "Allows this non-required field to validate when the value is empty"
- },
- "inputType": {
- "title": "HTML5 Input Type",
- "description": "Allows for the override of the underlying HTML5 input type. If not specified, an assumed value is provided based on the kind of input control (i.e. 'text', 'date', 'email' and so forth)",
- "type": "string"
- },
- "data": {
- "title": "Data attributes for the underlying DOM input control",
- "description": "Allows you to specify a key/value map of data attributes that will be added as DOM attribuets for the underlying input control. The data attributes will be added as data-{name}='{value}'.",
- "type": "object"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "size": {
- "type": "integer"
- },
- "maskString": {
- "helper": "a - an alpha character;9 - a numeric character;* - an alphanumeric character",
- "type": "text"
- },
- "typeahead": {
- "type": "object"
- },
- "allowOptionalEmpty": {
- "type": "checkbox"
- },
- "inputType": {
- "type": "text"
- },
- "data": {
- "type": "object"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "invalidPattern": "This field should have pattern {0}",
- "stringTooShort": "This field should contain at least {0} numbers or characters",
- "stringTooLong": "This field should contain at most {0} numbers or characters"
- });
- Alpaca.registerFieldClass("text", Alpaca.Fields.TextField);
- Alpaca.registerDefaultSchemaFieldMapping("string", "text");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextAreaField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.TextAreaField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function()
- {
- return "textarea";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.options.rows) {
- this.options.rows = 5;
- }
-
- if (!this.options.cols) {
- this.options.cols = 40;
- }
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": status
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"];
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.data;
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Multi-Line Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Textarea field for multiple line text.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rows": {
- "title": "Rows",
- "description": "Number of rows",
- "type": "number",
- "default": 5
- },
- "cols": {
- "title": "Columns",
- "description": "Number of columns",
- "type": "number",
- "default": 40
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rows": {
- "type": "integer"
- },
- "cols": {
- "type": "integer"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded."
- });
-
- Alpaca.registerFieldClass("textarea", Alpaca.Fields.TextAreaField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CheckBoxField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.CheckBoxField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "checkbox";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function() {
-
- var _this = this;
-
- _this.base();
-
- if (!this.options.rightLabel) {
- this.options.rightLabel = "";
- }
-
- if (typeof(_this.options.multiple) == "undefined")
- {
- if (_this.schema.type === "array")
- {
- _this.options.multiple = true;
- }
- else if (typeof(_this.schema["enum"]) != "undefined")
- {
- _this.options.multiple = true;
- }
- }
-
- _this.checkboxOptions = [];
- if (_this.options.multiple)
- {
- $.each(_this.getEnum(), function(index, value) {
-
- var text = value;
-
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.checkboxOptions.push({
- "value": value,
- "text": text
- });
- });
- }
- },
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- var array = [];
-
- if (this.schema && this.schema["enum"])
- {
- array = this.schema["enum"];
- }
-
- return array;
- },
-
- /**
- * Handler for the event that the checkbox is clicked.
- *
- * @param e Event.
- */
- onClick: function(e)
- {
- this.refreshValidationState();
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
- model.checkboxOptions = self.checkboxOptions;
-
- callback(model);
- });
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the checked state of the control to update
- if (self.data && typeof(self.data) !== "undefined")
- {
- self.setValue(self.data);
- }
-
- // whenever the state of one of our input:checkbox controls is changed (either via a click or programmatically),
- // we signal to the top-level field to fire up a change
- //
- // this allows the dependency system to recalculate and such
- //
- $(self.getFieldEl()).find("input:checkbox").change(function(evt) {
- self.triggerWithPropagation("change");
- });
-
- // for multiple mode, mark values
- if (self.options.multiple)
- {
- // none checked
- $(self.getFieldEl()).find("input:checkbox").prop("checked", false);
-
- if (self.data)
- {
- var dataArray = self.data;
- if (typeof(self.data) === "string")
- {
- dataArray = self.data.split(",");
- for (var a = 0; a < dataArray.length; a++)
- {
- dataArray[a] = $.trim(dataArray[a]);
- }
- }
-
- for (var k in dataArray)
- {
- $(self.getFieldEl()).find("input:checkbox[data-checkbox-value=\"" + dataArray[k] + "\"]").prop("checked", true);
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!self.options.multiple)
- {
- // single scalar value
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- value = Alpaca.checked($(input[0]));
- }
- else
- {
- value = false;
- }
- }
- else
- {
- // multiple values
- var values = [];
- for (var i = 0; i < self.checkboxOptions.length; i++)
- {
- var inputField = $(self.getFieldEl()).find("input[data-checkbox-index='" + i + "']");
- if (Alpaca.checked(inputField))
- {
- var v = $(inputField).attr("data-checkbox-value");
- values.push(v);
- }
- }
-
- // determine how we're going to hand this value back
-
- // if type == "array", we just hand back the array
- // if type == "string", we build a comma-delimited list
- if (self.schema.type === "array")
- {
- value = values;
- }
- else if (self.schema.type === "string")
- {
- value = values.join(",");
- }
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- // value can be a boolean, string ("true"), string ("a,b,c") or an array of values
-
- var applyScalarValue = function(value)
- {
- if (Alpaca.isString(value)) {
- value = (value === "true");
- }
-
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- };
-
- var applyMultiValue = function(values)
- {
- // allow for comma-delimited strings
- if (typeof(values) === "string")
- {
- values = values.split(",");
- }
-
- // trim things to remove any excess white space
- for (var i = 0; i < values.length; i++)
- {
- values[i] = Alpaca.trim(values[i]);
- }
-
- // walk through values and assign into appropriate inputs
- for (var j = 0; j < values.length; j++)
- {
- var input = $(self.getFieldEl()).find("input[data-checkbox-value=\"" + values[j] + "\"]");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- }
- };
-
- var applied = false;
-
- if (!self.options.multiple)
- {
- // single value mode
-
- // boolean
- if (typeof(value) === "boolean")
- {
- applyScalarValue(value);
- applied = true;
- }
- else if (typeof(value) === "string")
- {
- applyScalarValue(value);
- applied = true;
- }
- }
- else
- {
- // multiple value mode
-
- if (typeof(value) === "string")
- {
- applyMultiValue(value);
- applied = true;
- }
- else if (Alpaca.isArray(value))
- {
- applyMultiValue(value);
- applied = true;
- }
- }
-
- if (!applied && value)
- {
- Alpaca.logError("CheckboxField cannot set value for schema.type=" + self.schema.type + " and value=" + value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * Validate against enum property in the case that the checkbox field is in multiple mode.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var self = this;
-
- if (!self.options.multiple)
- {
- return true;
- }
-
- var val = self.getValue();
- if (!self.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- // if val is a string, convert to array
- if (typeof(val) === "string")
- {
- val = val.split(",");
- }
-
- return Alpaca.anyEquality(val, self.schema["enum"]);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = true;
- });
-
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = false;
- });
-
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "boolean";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Checkbox Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Checkbox Field for boolean (true/false), string ('true', 'false' or comma-delimited string of values) or data array.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rightLabel": {
- "title": "Option Label",
- "description": "Optional right-hand side label for single checkbox field.",
- "type": "string"
- },
- "multiple": {
- "title": "Multiple",
- "description": "Whether to render multiple checkboxes for multi-valued type (such as an array or a comma-delimited string)",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rightLabel": {
- "type": "text"
- },
- "multiple": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("checkbox", Alpaca.Fields.CheckBoxField);
- Alpaca.registerDefaultSchemaFieldMapping("boolean", "checkbox");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.FileField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.FileField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "file";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- this.data = value;
-
- this.data = value;
-
- this.updateObservable();
-
- this.triggerUpdate();
- },
-
- getValue: function()
- {
- return this.data;
- },
-
- onChange: function(e)
- {
- this.base(e);
-
- if (this.options.selectionHandler)
- {
- this.processSelectionHandler(e.target.files);
- }
- },
-
- processSelectionHandler: function(files)
- {
- if (files && files.length > 0)
- {
- // if the browser supports HTML5 FileReader, we can pull in the stream for preview
- if (typeof(FileReader) !== "undefined")
- {
- // clear out previous loaded data
- var loadedData = [];
- var loadCount = 0;
-
- var fileReader = new FileReader();
- fileReader.onload = (function() {
- var field = this;
- return function(event)
- {
- var dataUri = event.target.result;
-
- loadedData.push(dataUri);
- loadCount++;
-
- if (loadCount === files.length)
- {
- field.options.selectionHandler.call(field, files, loadedData);
- }
- };
- }).call(this);
-
- for (var i = 0; i < files.length; i++)
- {
- fileReader.readAsDataURL(files[i]);
- }
- }
- }
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "File Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for uploading files.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "selectionHandler": {
- "title": "Selection Handler",
- "description": "Function that should be called when files are selected. Requires HTML5.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "selectionHandler": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("file", Alpaca.Fields.FileField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ListField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ListField.prototype
- */
- {
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var _this = this;
-
- _this.base();
-
- _this.selectOptions = [];
-
- if (_this.getEnum())
- {
- $.each(_this.getEnum(), function(index, value)
- {
- var text = value;
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.selectOptions.push({
- "value": value,
- "text": text
- });
- });
- }
-
- /**
- * Auto assign data if we have data and the field is required and removeDefaultNone is either unspecified or true
- */
- if (_this.isRequired() && !_this.data)
- {
- //if ((typeof(_this.options.removeDefaultNone) == "undefined") || _this.options.removeDefaultNone === true)
- if ((_this.options.removeDefaultNone === true))
- {
- if (_this.schema.enum && _this.schema.enum.length > 0)
- {
- _this.data = _this.schema.enum[0];
- }
- }
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.noneLabel = "None";
- if (typeof(self.options.noneLabel) != "undefined")
- {
- model.noneLabel = self.options.noneLabel;
- }
-
- model.hideNone = self.isRequired();
- if (typeof(self.options.removeDefaultNone) != "undefined")
- {
- model.hideNone = self.options.removeDefaultNone;
- }
-
- callback(model);
- });
- },
-
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- if (this.schema && this.schema["enum"])
- {
- return this.schema["enum"];
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function(val)
- {
- var _this = this;
- if (Alpaca.isArray(val))
- {
- $.each(val, function(index, itemVal) {
- $.each(_this.selectOptions, function(index2, selectOption) {
-
- if (selectOption.value === itemVal)
- {
- val[index] = selectOption.value;
- }
-
- });
- });
- }
- else
- {
- $.each(this.selectOptions, function(index, selectOption) {
-
- if (selectOption.value === val)
- {
- val = selectOption.value;
- }
-
- });
- }
- return val;
- },
-
- /**
- * @see Alpaca.ControlField#beforeRenderControl
- */
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.options.dataSource)
- {
- self.selectOptions = [];
-
- var completionFunction = function()
- {
- self.schema.enum = [];
- self.options.optionLabels = [];
-
- for (var i = 0; i < self.selectOptions.length; i++)
- {
- self.schema.enum.push(self.selectOptions[i].value);
- self.options.optionLabels.push(self.selectOptions[i].text);
- }
-
- // push back to model
- model.selectOptions = self.selectOptions;
-
- callback();
- };
-
- if (Alpaca.isFunction(self.options.dataSource))
- {
- self.options.dataSource.call(self, function(values) {
-
- if (Alpaca.isArray(values))
- {
- for (var i = 0; i < values.length; i++)
- {
- if (typeof(values[i]) === "string")
- {
- self.selectOptions.push({
- "text": values[i],
- "value": values[i]
- });
- }
- else if (Alpaca.isObject(values[i]))
- {
- self.selectOptions.push(values[i]);
- }
- }
-
- completionFunction();
- }
- else if (Alpaca.isObject(values))
- {
- for (var k in values)
- {
- self.selectOptions.push({
- "text": k,
- "value": values[k]
- });
- }
-
- completionFunction();
- }
- else
- {
- completionFunction();
- }
- });
- }
- else if (Alpaca.isUri(self.options.dataSource))
- {
- $.ajax({
- url: self.options.dataSource,
- type: "get",
- dataType: "json",
- success: function(jsonDocument) {
-
- var ds = jsonDocument;
- if (self.options.dsTransformer && Alpaca.isFunction(self.options.dsTransformer))
- {
- ds = self.options.dsTransformer(ds);
- }
-
- if (ds)
- {
- if (Alpaca.isObject(ds))
- {
- // for objects, we walk through one key at a time
- // the insertion order is the order of the keys from the map
- // to preserve order, consider using an array as below
- $.each(ds, function(key, value) {
- self.selectOptions.push({
- "value": key,
- "text": value
- });
- });
-
- completionFunction();
- }
- else if (Alpaca.isArray(ds))
- {
- // for arrays, we walk through one index at a time
- // the insertion order is dictated by the order of the indices into the array
- // this preserves order
- $.each(ds, function(index, value) {
- self.selectOptions.push({
- "value": value.value,
- "text": value.text
- });
- });
-
- completionFunction();
- }
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
-
- self.errorCallback({
- "message":"Unable to load data from uri : " + _this.options.dataSource,
- "stage": "DATASOURCE_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- });
- }
- else if (Alpaca.isArray(self.options.dataSource))
- {
- for (var i = 0; i < self.options.dataSource.length; i++)
- {
- if (typeof(self.options.dataSource[i]) === "string")
- {
- self.selectOptions.push({
- "text": self.options.dataSource[i],
- "value": self.options.dataSource[i]
- });
- }
- else if (Alpaca.isObject(self.options.dataSource[i]))
- {
- self.selectOptions.push(self.options.dataSource[i]);
- }
- }
-
- completionFunction();
- }
- else
- {
- callback();
- }
- }
- else
- {
- callback();
- }
-
- });
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumeration",
- "description": "List of field value options",
- "type": "array",
- "required": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "optionLabels": {
- "title": "Option Labels",
- "description": "Labels for options. It can either be a map object or an array field that maps labels to items defined by enum schema property one by one.",
- "type": "array"
- },
- "dataSource": {
- "title": "Option Datasource",
- "description": "Datasource for generating list of options. This can be a string or a function. If a string, it is considered to be a URI to a service that produces a object containing key/value pairs or an array of elements of structure {'text': '', 'value': ''}. This can also be a function that is called to produce the same list.",
- "type": "string"
- },
- "removeDefaultNone": {
- "title": "Remove Default None",
- "description": "If true, the default 'None' option will not be shown.",
- "type": "boolean",
- "default": false
- },
- "noneLabel": {
- "title": "None Label",
- "description": "The label to use for the 'None' option in a list (select, radio or otherwise).",
- "type": "string",
- "default": "None"
- },
- "hideNone": {
- "title": "Hide None",
- "description": "Whether to hide the None option from a list (select, radio or otherwise). This will be true if the field is required and false otherwise.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "optionLabels": {
- "itemLabel":"Label",
- "type": "array"
- },
- "dataSource": {
- "type": "text"
- },
- "removeDefaultNone": {
- "type": "checkbox",
- "rightLabel": "Remove Default None"
- },
- "noneLabel": {
- "type": "text"
- },
- "hideNone": {
- "type": "checkbox",
- "rightLabel": "Hide the 'None' option from the list"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-})(jQuery);
-
-(function($){
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.RadioField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.RadioField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "radio";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.options.name)
- {
- this.name = this.options.name;
- }
- else if (!this.name)
- {
- this.name = this.getId() + "-name";
- }
-
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.emptySelectFirst))
- {
- this.options.emptySelectFirst = false;
- }
-
- // assume vertical orientation
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.vertical))
- {
- this.options.vertical = true;
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var val = null;
-
- $(this.control).find(":checked").each(function() {
- val = $(this).val();
-
- val = self.ensureProperType(val);
- });
-
- return val;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- var self = this;
-
- // clear all
- $(this.control).find("input").each(function() {
- Alpaca.checked($(this), null);
- });
-
- // mark selected value
- if (typeof(val) != "undefined")
- {
- Alpaca.checked($(self.control).find("input[value=\"" + val + "\"]"), "checked");
- }
-
- // if none selected and "emptySelectFirst", then select
- if (this.options.emptySelectFirst)
- {
- if ($(this.control).find("input:checked").length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio").first(), "checked");
- }
- }
-
- this.base(val);
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- var inputs = $(this.control).find("input");
-
- inputs.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- inputs.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
- model.removeDefaultNone = self.options.removeDefaultNone;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
-
- if ($("input:radio:checked", self.control).length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio[value=\"" + self.data + "\"]"), "checked");
- }
- }
-
- // stack radio selectors vertically
- if (self.options.vertical)
- {
- $(self.control).css("display", "block");
- }
- else
- {
- $(self.control).css("display", "inline-block");
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.ControlField#onClick
- */
- onClick: function(e)
- {
- this.base(e);
-
- var self = this;
-
- var val = $(e.currentTarget).find("input").val();
- if (typeof(val) != "undefined")
- {
- self.setValue(val);
- self.refreshValidationState();
- }
-
- /*
- Alpaca.later(25, this, function(){
- var v = self.getValue();
- self.setValue(v);
- self.refreshValidationState();
- });
- */
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Radio Group Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Radio Group Field with list of options.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function()
- {
- return Alpaca.merge(this.base(),{
- "properties": {
- "name": {
- "title": "Field name",
- "description": "Field name.",
- "type": "string"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "vertical": {
- "title": "Position the radio selector items vertically",
- "description": "By default, radio controls are stacked vertically. Set to false if you'd like radio controls to lay out horizontally.",
- "type": "boolean",
- "default": true
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("radio", Alpaca.Fields.RadioField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SelectField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.SelectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function()
- {
- return "select";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- if (this.control && this.control.length > 0)
- {
- var val = this._getControlVal(true);
- if (typeof(val) === "undefined")
- {
- val = this.data;
- }
-
- return this.base(val);
- }
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- if (Alpaca.isArray(val))
- {
- if (!Alpaca.compareArrayContent(val, this.getValue()))
- {
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- else
- {
- if (val !== this.getValue())
- {
- /*
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
- */
- if (this.control && typeof(val) != "undefined" && val != null)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- },
-
- /**
- * @see Alpaca.ListField#getEnum
- */
- getEnum: function()
- {
- if (this.schema)
- {
- if (this.schema["enum"])
- {
- return this.schema["enum"];
- }
- else if (this.schema["type"] && this.schema["type"] === "array" && this.schema["items"] && this.schema["items"]["enum"])
- {
- return this.schema["items"]["enum"];
- }
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- if (self.options.multiple)
- {
- var button = this.control.parent().find("button.multiselect");
-
- button.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- button.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- }
- },
-
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.schema["type"] && self.schema["type"] === "array")
- {
- self.options.multiple = true;
- }
-
- callback();
-
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (Alpaca.isUndefined(self.data) && self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
- }
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the state of the control
- if (self.data)
- {
- self.setValue(self.data);
- }
-
- // if we are in multiple mode and the bootstrap multiselect plugin is available, bind it in
- if (self.options.multiple && $.fn.multiselect)
- {
- var settings = null;
- if (self.options.multiselect) {
- settings = self.options.multiselect;
- }
- else
- {
- settings = {};
- }
- if (!settings.nonSelectedText)
- {
- settings.nonSelectedText = "None";
- if (self.options.noneLabel)
- {
- settings.nonSelectedText = self.options.noneLabel;
- }
- }
- if (self.options.hideNone)
- {
- delete settings.nonSelectedText;
- }
-
- $(self.getControlEl()).multiselect(settings);
- }
-
- callback();
-
- });
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var _this = this;
-
- if (this.schema["enum"])
- {
- var val = this.data;
-
- if (!this.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- if (this.options.multiple)
- {
- var isValid = true;
-
- if (!val)
- {
- val = [];
- }
-
- if (!Alpaca.isArray(val) && !Alpaca.isObject(val))
- {
- val = [val];
- }
-
- $.each(val, function(i,v) {
-
- if ($.inArray(v, _this.schema["enum"]) <= -1)
- {
- isValid = false;
- return false;
- }
-
- });
-
- return isValid;
- }
- else
- {
- return ($.inArray(val, this.schema["enum"]) > -1);
- }
- }
- else
- {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- _this.refreshValidationState();
- });
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if ($(":selected",this.control).length < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if ($(":selected",this.control).length > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Select Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Select Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multiple": {
- "title": "Mulitple Selection",
- "description": "Allow multiple selection if true.",
- "type": "boolean",
- "default": false
- },
- "size": {
- "title": "Displayed Options",
- "description": "Number of options to be shown.",
- "type": "number"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "multiselect": {
- "title": "Multiselect Plugin Settings",
- "description": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multiple": {
- "rightLabel": "Allow multiple selection ?",
- "helper": "Allow multiple selection if checked",
- "type": "checkbox"
- },
- "size": {
- "type": "integer"
- },
- "emptySelectFirst": {
- "type": "checkbox",
- "rightLabel": "Empty Select First"
- },
- "multiselect": {
- "type": "object",
- "rightLabel": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("select", Alpaca.Fields.SelectField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.NumberField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.NumberField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "number";
- //this.inputType = "number";
- // TODO: we can't do this because Chrome screws up it's handling of number type
- // and prevents us from validating properly
- // @see http://stackoverflow.com/questions/16420828/jquery-val-refuses-to-return-non-numeric-input-from-a-number-field-under-chrome
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "number";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var val = this._getControlVal(true);
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseFloat(val);
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateNumber();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotANumber"),
- "status": status
- };
-
- status = this._validateDivisibleBy();
- valInfo["stringDivisibleBy"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringDivisibleBy"), [this.schema.divisibleBy]),
- "status": status
- };
-
- status = this._validateMaximum();
- valInfo["stringValueTooLarge"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMaximum) {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLargeExclusive"), [this.schema.maximum]);
- } else {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLarge"), [this.schema.maximum]);
- }
- }
-
- status = this._validateMinimum();
- valInfo["stringValueTooSmall"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMinimum) {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmallExclusive"), [this.schema.minimum]);
- } else {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmall"), [this.schema.minimum]);
- }
- }
-
- status = this._validateMultipleOf();
- valInfo["stringValueNotMultipleOf"] = {
- "message": "",
- "status": status
- };
- if (!status)
- {
- valInfo["stringValueNotMultipleOf"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueNotMultipleOf"), [this.schema.multipleOf]);
- }
-
- // hand back a true/false
- return baseStatus && valInfo["stringNotANumber"]["status"] && valInfo["stringDivisibleBy"]["status"] && valInfo["stringValueTooLarge"]["status"] && valInfo["stringValueTooSmall"]["status"] && valInfo["stringValueNotMultipleOf"]["status"];
- },
-
- /**
- * Validates if it is a float number.
- * @returns {Boolean} true if it is a float number
- */
- _validateNumber: function() {
-
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid number format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.number, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * Validates divisibleBy constraint.
- * @returns {Boolean} true if it passes the divisibleBy constraint.
- */
- _validateDivisibleBy: function() {
- var floatValue = this.getValue();
- if (!Alpaca.isEmpty(this.schema.divisibleBy)) {
-
- // mod
- if (floatValue % this.schema.divisibleBy !== 0)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the maximum constraint.
- */
- _validateMaximum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.maximum)) {
- if (floatValue > this.schema.maximum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMaximum)) {
- if (floatValue == this.schema.maximum && this.schema.exclusiveMaximum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the minimum constraint.
- */
- _validateMinimum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.minimum)) {
- if (floatValue < this.schema.minimum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMinimum)) {
- if (floatValue == this.schema.minimum && this.schema.exclusiveMinimum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates multipleOf constraint.
- * @returns {Boolean} true if it passes the multipleOf constraint.
- */
- _validateMultipleOf: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.multipleOf)) {
- if (floatValue && this.schema.multipleOf !== 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "number";
- },
-
- /* builder_helpers */
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "Property value must be a multiple of the multipleOf schema property such that division by this value yields an interger (mod zero).",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "number"
- },
- "exclusiveMinimum": {
- "title": "Exclusive Minimum",
- "description": "Property value can not equal the number defined by the minimum schema property.",
- "type": "boolean",
- "default": false
- },
- "exclusiveMaximum": {
- "title": "Exclusive Maximum",
- "description": "Property value can not equal the number defined by the maximum schema property.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "The value must be a integral multiple of the property",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property",
- "type": "number"
- },
- "exclusiveMinimum": {
- "rightLabel": "Exclusive minimum ?",
- "helper": "Field value must be greater than but not equal to this number if checked",
- "type": "checkbox"
- },
- "exclusiveMaximum": {
- "rightLabel": "Exclusive Maximum ?",
- "helper": "Field value must be less than but not equal to this number if checked",
- "type": "checkbox"
- }
- }
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Number Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for float numbers.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringValueTooSmall": "The minimum value for this field is {0}",
- "stringValueTooLarge": "The maximum value for this field is {0}",
- "stringValueTooSmallExclusive": "Value of this field must be greater than {0}",
- "stringValueTooLargeExclusive": "Value of this field must be less than {0}",
- "stringDivisibleBy": "The value must be divisible by {0}",
- "stringNotANumber": "This value is not a number.",
- "stringValueNotMultipleOf": "This value is not a multiple of {0}"
- });
- Alpaca.registerFieldClass("number", Alpaca.Fields.NumberField);
- Alpaca.registerDefaultSchemaFieldMapping("number", "number");
-
-})(jQuery);
-
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ArrayField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ArrayField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "array";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = Alpaca.isEmpty(this.view.toolbarStyle) ? "button" : this.view.toolbarStyle;
- }
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = "button";
- }
-
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = Alpaca.isEmpty(this.view.actionbarStyle) ? "top" : this.view.actionbarStyle;
- }
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = "top";
- }
-
- // determine whether we are using "ruby on rails" compatibility mode
- this.options.rubyrails = false;
- if (this.parent && this.parent.options && this.parent.options.form && this.parent.options.form.attributes)
- {
- if (!Alpaca.isEmpty(this.parent.options.form.attributes.rubyrails))
- {
- this.options.rubyrails = true;
- }
- }
-
- if (!this.options.items)
- {
- this.options.items = {};
- }
-
- var toolbarSticky = true;
-
- if (!Alpaca.isEmpty(this.view.toolbarSticky))
- {
- toolbarSticky = this.view.toolbarSticky;
- }
-
- if (!Alpaca.isEmpty(this.options.toolbarSticky))
- {
- toolbarSticky = this.options.toolbarSticky;
- }
-
- this.options.toolbarSticky = toolbarSticky;
-
- // Enable forceRevalidation option so that any change in children will trigger parent's revalidation.
- if (this.schema.items && this.schema.uniqueItems)
- {
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
- }
-
- if (typeof(this.data) == "undefined")
- {
- this.data = [];
- }
-
- if (this.data == null)
- {
- this.data = [];
- }
-
- if ("" == this.data)
- {
- this.data = [];
- }
-
- if (Alpaca.isString(this.data))
- {
- // assume to be a serialized array or object, convert
- try
- {
- var parsedJSON = Alpaca.parseJSON(this.data);
-
- if (!Alpaca.isArray(parsedJSON) && !Alpaca.isObject(parsedJSON))
- {
- Alpaca.logWarn("ArrayField parsed string data but it was not an array: " + this.data);
- return;
- }
-
- this.data = parsedJSON;
- }
- catch (e)
- {
- // assume just a string value, put into array
- this.data = [this.data];
- }
- }
-
- if (!Alpaca.isArray(this.data) && !Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ArrayField data is not an array: " + JSON.stringify(this.data, null, " "));
- return;
- }
-
- //
- // ACTIONS
- //
- var applyAction = function(actions, key, actionConfig) {
- var action = self.findAction(actions, key);
- if (!action) {
- action = {
- "core": true
- };
- actions.push(action);
- }
- for (var k in actionConfig) {
- action[k] = actionConfig[k];
- }
- };
- var cleanupActions = function(actions, showLabels) {
- var i = 0;
- do {
-
- // assume enabled by default
- if (typeof(actions[i].enabled) === "undefined") {
- actions[i].enabled = true;
- }
-
- // hide label if global disable
- if (!showLabels) {
- delete actions[i].label;
- }
-
- if (!actions[i].enabled) {
- actions.splice(i, 1);
- } else {
- i++;
- }
-
- } while (i < actions.length);
-
- // sort so that core actions appear first
- actions.sort(function(a, b) {
- if (a.core && !b.core) {
- return -1;
- }
- if (!a.core && b.core) {
- return 1;
- }
- return 0;
- });
- };
-
- // set up default actions for the top array toolbar
- self.toolbar = {};
- if (self.options.toolbar)
- {
- for (var k in self.options.toolbar) {
- self.toolbar[k] = self.options.toolbar[k];
- }
- }
- if (typeof(self.toolbar.showLabels) === "undefined") {
- self.toolbar.showLabels = false;
- }
- if (!self.toolbar.actions) {
- self.toolbar.actions = [];
- }
- applyAction(self.toolbar.actions, "add", {
- "label": "Add New Item",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action)
- {
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(0, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
- }
- });
- cleanupActions(self.toolbar.actions, self.toolbar.showLabels);
-
- // determine which actions to add into the per-item actionbar
- self.actionbar = {};
- if (self.options.actionbar)
- {
- for (var k2 in self.options.actionbar) {
- self.actionbar[k2] = self.options.actionbar[k2];
- }
- }
- if (typeof(self.actionbar.showLabels) === "undefined") {
- self.actionbar.showLabels = false;
- }
- if (!self.actionbar.actions) {
- self.actionbar.actions = [];
- }
- applyAction(self.actionbar.actions, "add", {
- "label": "Add",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action, itemIndex) {
-
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(itemIndex + 1, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
-
- }
- });
- applyAction(self.actionbar.actions, "remove", {
- "label": "Remove",
- "action": "remove",
- "iconClass": self.view.getStyle("removeIcon"),
- "click": function(key, action, itemIndex) {
-
- self.removeItem(itemIndex, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "up", {
- "label": "Up",
- "action": "up",
- "iconClass": self.view.getStyle("upIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex - 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "down", {
- "label": "Down",
- "action": "down",
- "iconClass": self.view.getStyle("downIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex + 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- cleanupActions(self.actionbar.actions, self.actionbar.showLabels);
-
- var len = this.data.length;
- var data = $.extend(true, {}, this.data);
- data.length = len;
-
- this.data = Array.prototype.slice.call(data);
- },
-
- /**
- * Picks apart the array and set onto child fields.
- * @see Alpaca.ContainerField#setup
- */
- setValue: function(data)
- {
- var self = this;
-
- if (!data || !Alpaca.isArray(data))
- {
- return;
- }
-
- // set fields
- var i = 0;
- do
- {
- if (i < self.children.length)
- {
- var childField = self.children[i];
-
- if (data.length > i)
- {
- childField.setValue(data[i]);
- i++;
- }
- else
- {
- self.removeItem(i);
- }
- }
- }
- while (i < self.children.length);
-
- // if the number of items in the data is greater than the number of existing child elements
- // then we need to add the new fields
- if (i < data.length)
- {
- self.resolveItemSchemaOptions(function(schema, options) {
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for item: " + i);
- }
-
- // waterfall functions
- var funcs = [];
-
- while (i < data.length)
- {
- var f = (function(i, data)
- {
- return function(callback)
- {
- self.addItem(i, schema, options, data[i], function() {
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
- })(i, data[i]);
-
- funcs.push(f);
-
- i++;
- }
-
- Alpaca.series(funcs, function() {
- // nothing
- });
- });
- }
-
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we're empty and we're also not required, then we hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // otherwise, construct an array and had it back
- var o = [];
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
-
- if (typeof(v) !== "undefined")
- {
- o.push(v);
- }
- }
- return o;
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var self = this;
-
- var items = [];
-
- if (self.data)
- {
- // all items within the array have the same schema and options
- // so we only need to load this once
- self.resolveItemSchemaOptions(function(schema, options) {
-
- // waterfall functions
- var funcs = [];
- for (var index = 0; index < self.data.length; index++)
- {
- var value = self.data[index];
-
- var pf = (function(index, value)
- {
- return function(callback)
- {
- self.createItem(index, schema, options, value, function(item) {
-
- items.push(item);
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
-
- })(index, value);
-
- funcs.push(pf);
- }
-
- Alpaca.series(funcs, function(err) {
- callback(items);
- });
-
- });
- }
- else
- {
- callback(items);
- }
- },
-
- /**
- * Workhorse method for createItem.
- *
- * @param index
- * @param itemSchema
- * @param itemOptions
- * @param itemData
- * @param postRenderCallback
- * @return {*}
- * @private
- */
- createItem: function(index, itemSchema, itemOptions, itemData, postRenderCallback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render": function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // setup item path
- fieldControl.path = self.path + "[" + index + "]";
- //fieldControl.nameCalculated = true;
- fieldControl.render(null, function() {
-
- // remember the control
- self.refreshValidationState();
- self.updatePathAndName();
-
- // trigger update on the parent array
- self.triggerUpdate();
-
- if (cb)
- {
- cb();
- }
- });
- },
- "postRender": function(control)
- {
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- // PR: https://github.com/gitana/alpaca/pull/124
- if (Alpaca.isFunction(self.options.items.postRender))
- {
- self.options.items.postRender.call(control, insertionPointEl);
- }
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- }
- },
-
- /**
- * Determines the schema and options to utilize for items within this array.
- *
- * @param callback
- */
- resolveItemSchemaOptions: function(callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedItemSchema, resolvedItemOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedItemOptions.readonly = true;
- }
-
- callback(resolvedItemSchema, resolvedItemOptions, circular);
- };
-
- var itemOptions;
- // legacy support for options.fields.item
- if (!itemOptions && _this.options && _this.options.fields && _this.options.fields.item) {
- itemOptions = _this.options.fields.item;
- }
- if (!itemOptions && _this.options && _this.options.items) {
- itemOptions = _this.options.items;
- }
- var itemSchema;
- if (_this.schema && _this.schema.items) {
- itemSchema = _this.schema.items;
- }
-
- // handle $ref
- if (itemSchema && itemSchema["$ref"])
- {
- var referenceId = itemSchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalItemSchema = itemSchema;
- var originalItemOptions = itemOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(itemSchema, itemOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedItemSchema = {};
- if (originalItemSchema) {
- Alpaca.mergeObject(resolvedItemSchema, originalItemSchema);
- }
- if (itemSchema)
- {
- Alpaca.mergeObject(resolvedItemSchema, itemSchema);
- }
- delete resolvedItemSchema.id;
-
- var resolvedItemOptions = {};
- if (originalItemOptions) {
- Alpaca.mergeObject(resolvedItemOptions, originalItemOptions);
- }
- if (itemOptions)
- {
- Alpaca.mergeObject(resolvedItemOptions, itemOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedItemSchema, resolvedItemOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(itemSchema, itemOptions);
- });
- }
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateUniqueItems();
- valInfo["valueNotUnique"] = {
- "message": status ? "" : this.view.getMessage("valueNotUnique"),
- "status": status
- };
-
- status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["valueNotUnique"]["status"] && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- },
-
- /**
- * Validates if the number of items has been reached to maxItems.
- * @returns {Boolean} true if the number of items has been reached to maxItems
- */
- _validateEqualMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() >= this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if the number of items has been reached to minItems.
- * @returns {Boolean} true if number of items has been reached to minItems
- */
- _validateEqualMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() <= this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if all items are unique.
- * @returns {Boolean} true if all items are unique.
- */
- _validateUniqueItems: function()
- {
- if (this.schema.items && this.schema.uniqueItems)
- {
- var hash = {};
- for (var i = 0, l = this.children.length; i < l; ++i)
- {
- if (!hash.hasOwnProperty(this.children[i]))
- {
- hash[this.children[i]] = true;
- }
- else
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- findAction: function(actionsArray, actionKey)
- {
- var action = null;
-
- $.each(actionsArray, function(i, v) {
- if (v.action == actionKey) // jshint ignore:line
- {
- action = v;
- }
- });
-
- return action;
- },
-
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
-
- });
- },
-
- /*
- afterApplyCreatedItems: function(model, callback)
- {
- var self = this;
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
- },
- */
-
- /**
- * Returns number of children.
- */
- getSize: function() {
- return this.children.length;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updatePathAndName: function()
- {
- var self = this;
-
- var updateChildrenPathAndName = function(parent)
- {
- if (parent.children)
- {
- $.each(parent.children, function(i, v) {
-
- if (parent.prePath && Alpaca.startsWith(v.path,parent.prePath))
- {
- v.prePath = v.path;
- v.path = v.path.replace(parent.prePath,parent.path);
- }
-
- // re-calculate name
- if (parent.preName && Alpaca.startsWith(v.name, parent.preName))
- {
- v.preName = v.name;
- v.name = v.name.replace(parent.preName, parent.name);
- if (v.field)
- {
- $(v.field).attr('name', v.name);
- }
- }
-
- updateChildrenPathAndName(v);
- });
- }
- };
-
- if (this.children && this.children.length > 0)
- {
- $.each(this.children, function(i, v) {
-
- var idx = v.path.lastIndexOf('/');
- var lastSegment = v.path.substring(idx+1);
- if (lastSegment.indexOf("[") < 0 && lastSegment.indexOf("]") < 0)
- {
- lastSegment = lastSegment.substring(lastSegment.indexOf("[") + 1, lastSegment.indexOf("]"));
- }
-
- if (lastSegment !== i)
- {
- v.prePath = v.path;
- v.path = v.path.substring(0, idx) + "/[" + i + "]";
- }
-
- // re-calculate name
- if (v.nameCalculated)
- {
- v.preName = v.name;
-
- if (v.parent && v.parent.name && v.path)
- {
- v.name = v.parent.name + "_" + i;
- }
- else
- {
- if (v.path)
- {
- v.name = v.path.replace(/\//g, "").replace(/\[/g, "_").replace(/\]/g, "");
- }
- }
-
- if (this.parent.options.rubyrails )
- {
- $(v.field).attr('name', v.parent.name);
- }
- else
- {
- $(v.field).attr('name', v.name);
- }
-
- }
-
- if (!v.prePath)
- {
- v.prePath = v.path;
- }
-
- updateChildrenPathAndName(v);
- });
- }
- },
-
- /**
- * Updates the status of array item action toolbar buttons.
- */
- updateToolbars: function()
- {
- var self = this;
-
- // if we're in display mode, we do not do this
- if (this.view.type === "display")
- {
- return;
- }
-
- // if we're in readonly mode, don't do this
- if (this.schema.readonly)
- {
- return;
- }
-
- // fire callbacks to view to remove and create toolbar
- if (self.toolbar)
- {
- self.fireCallback("arrayToolbar", true);
- self.fireCallback("arrayToolbar");
- }
-
- // fire callbacks to view to remove and create an actionbar for each item
- if (self.actionbar)
- {
- self.fireCallback("arrayActionbars", true);
- self.fireCallback("arrayActionbars");
- }
-
- //
- // TOOLBAR
- //
-
- var toolbarEl = $(this.getFieldEl()).find(".alpaca-array-toolbar[data-alpaca-array-toolbar-field-id='" + self.getId() + "']");
- if (this.children.length > 0)
- {
- // hide toolbar
- $(toolbarEl).hide();
- }
- else
- {
- // show toolbar
- $(toolbarEl).show();
-
- // CLICK: array toolbar buttons
- $(toolbarEl).find("[data-alpaca-array-toolbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-toolbar-action");
- var action = self.findAction(self.toolbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action);
- });
- }
- });
- }
-
-
- //
- // ACTIONBAR
- //
-
- // if we're not using the "sticky" toolbar, then show and hide the item action buttons when hovered
- if (!this.options.toolbarSticky)
- {
- // find each item
- var items = this.getFieldEl().find(".alpaca-container-item");
- $(items).each(function(itemIndex) {
-
- // find the actionbar for this item
- // find from containerItemEl
- var actionbarEl = $(self.containerItemEl).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "'][data-alpaca-array-actionbar-item-index='" + itemIndex + "']");
- if (actionbarEl && actionbarEl.length > 0)
- {
- $(this).hover(function() {
- $(actionbarEl).show();
- }, function() {
- $(actionbarEl).hide();
- });
-
- $(actionbarEl).hide();
- }
- });
- }
- else
- {
- // otherwise, always show the actionbars
- $(self.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "']").show();
- }
-
- // CLICK: actionbar buttons
- var actionbarEls = $(this.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-parent-field-id='" + self.getId() + "']");
- $(actionbarEls).each(function() {
-
- var targetIndex = $(this).attr("data-alpaca-array-actionbar-item-index");
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- // bind button click handlers
- $(this).find("[data-alpaca-array-actionbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-actionbar-action");
- var action = self.findAction(self.actionbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action, targetIndex);
- });
- }
- });
-
- // if we're at max capacity, disable "add" buttons
- if (self._validateEqualMaxItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
-
- // if we're at min capacity, disable "remove" buttons
- if (self._validateEqualMinItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
- });
- // first actionbar has its "move up" button disabled
- $(actionbarEls).first().find("[data-alpaca-array-actionbar-action='up']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- // last actionbar has its "move down" button disabled
- $(actionbarEls).last().find("[data-alpaca-array-actionbar-action='down']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
-
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- doResolveItemContainer: function()
- {
- var self = this;
-
- return $(self.container);
- },
-
- doAddItem: function(index, item)
- {
- var self = this;
-
- var addItemContainer = self.doResolveItemContainer();
-
- // insert into dom
- if (index === 0)
- {
- // insert first into container
- $(addItemContainer).append(item.containerItemEl);
- }
- else
- {
- // insert at a specific index
- var existingElement = addItemContainer.children("[data-alpaca-container-item-index='" + (index-1) + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(item.containerItemEl);
- }
- }
-
- self.doAfterAddItem(item);
- },
-
- doAfterAddItem: function(item)
- {
-
- },
-
- /**
- * Adds an item to the array.
- *
- * This gets called from the toolbar when items are added via the user interface. The method can also
- * be called programmatically to insert items on the fly.
- *
- * @param {Integer} index the index where the item should be inserted
- * @param {Object} schema the json schema
- * @param {Object} options the json options
- * @param {Any} data the data for the newly inserted item
- * @param [Function] callback called after the child is added
- */
- addItem: function(index, schema, options, data, callback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- self.createItem(index, schema, options, data, function(item) {
-
- // register the child
- self.registerChild(item, index);
-
- // insert into dom
- self.doAddItem(index, item);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- }
- },
-
- doRemoveItem: function(childIndex)
- {
- var self = this;
-
- var removeItemContainer = self.doResolveItemContainer();
-
- removeItemContainer.children(".alpaca-container-item[data-alpaca-container-item-index='" + childIndex + "']").remove();
- },
-
- /**
- * Removes an item from the array.
- *
- * This gets called automatically from setValue() when the number of items being set is less than the number
- * of field elements.
-
- * @param {Number} childIndex index of the child to be removed
- * @param [Function] callback called after the child is removed
- */
- removeItem: function(childIndex, callback)
- {
- var self = this;
-
- if (this._validateEqualMinItems())
- {
- // unregister the child
- self.unregisterChild(childIndex);
-
- // remove itemContainerEl from DOM
- self.doRemoveItem(childIndex);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- }
- },
-
- /**
- * Dynamically moves a child to a new index in the array.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to be moved to
- * @param {Boolean} animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- if (sourceIndex === targetIndex)
- {
- // nothing to do
- return;
- }
-
- //console.log("Source: " + sourceIndex + ", Target: " + targetIndex);
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- var parentFieldId = self.getId();
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + sourceIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
- var targetContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + targetIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- var duration = 0;
- if (animate)
- {
- duration = 500;
- }
-
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, duration, function() {
- onComplete();
- });
- },
-
- /**
- * @see Alpaca.ContainerField#getType
- */
- getType: function() {
- return "array";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.ContainerField#getTitle
- */
- getTitle: function() {
- return "Array Field";
- },
-
- /**
- * @see Alpaca.ContainerField#getDescription
- */
- getDescription: function() {
- return "Field for list of items with same data type or structure.";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "items": {
- "title": "Array Items",
- "description": "Schema for array items.",
- "type": "object",
- "properties": {
- "minItems": {
- "title": "Minimum Items",
- "description": "Minimum number of items.",
- "type": "number"
- },
- "maxItems": {
- "title": "Maximum Items",
- "description": "Maximum number of items.",
- "type": "number"
- },
- "uniqueItems": {
- "title": "Items Unique",
- "description": "Item values should be unique if true.",
- "type": "boolean",
- "default": false
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "items": {
- "type": "object",
- "fields": {
- "minItems": {
- "type": "integer"
- },
- "maxItems": {
- "type": "integer"
- },
- "uniqueItems": {
- "type": "checkbox"
- }
- }
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var properties = {
- "properties": {
- "toolbarSticky": {
- "title": "Sticky Toolbar",
- "description": "Array item toolbar will be aways on if true.",
- "type": "boolean",
- "default": false
- },
- "toolbarStyle": {
- "title": "Toolbar Style",
- "description": "The kind of top-level toolbar to render for the array field. Either 'button' or 'link'.",
- "type": "string",
- "default": "button"
- },
- "actionbarStyle": {
- "title": "Actionbar Style",
- "description": "The kind of actionbar to render for each item in the array. Either 'top', 'bottom', 'left', or 'right'.",
- "type": "string",
- "default": "top"
- },
- "toolbar": {
- "type": "object",
- "title": "Toolbar Configuration",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Toolbar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- },
- "actionbar": {
- "type": "object",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Actions Bar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "toolbarSticky": {
- "type": "checkbox"
- },
- "items": {
- "type": "object",
- "fields": {
- }
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "notEnoughItems": "The minimum number of items is {0}",
- "tooManyItems": "The maximum number of items is {0}",
- "valueNotUnique": "Values are not unique",
- "notAnArray": "This value is not an Array"
- });
- Alpaca.registerFieldClass("array", Alpaca.Fields.ArrayField);
- Alpaca.registerDefaultSchemaFieldMapping("array", "array");
-
-})(jQuery);
-
-/*jshint -W004 */ // duplicate variables
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ObjectField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ObjectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "object";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- var x = self.resolveContainerItemTemplateType();
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
-
- if (this.data === "")
- {
- return;
- }
-
- if (!Alpaca.isObject(this.data))
- {
- if (!Alpaca.isString(this.data))
- {
- return;
- }
- else
- {
- try
- {
- this.data = Alpaca.parseJSON(this.data);
- if (!Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ObjectField parsed data but it was not an object: " + JSON.stringify(this.data));
- return;
- }
- }
- catch (e)
- {
- return;
- }
- }
- }
- },
-
- /**
- * Picks apart the data object and set onto child fields.
- *
- * @see Alpaca.Field#setValue
- */
- setValue: function(data)
- {
- if (!data)
- {
- data = {};
- }
-
- // if not an object by this point, we don't handle it
- if (!Alpaca.isObject(data))
- {
- return;
- }
-
- // sort existing fields by property id
- var existingFieldsByPropertyId = {};
- for (var fieldId in this.childrenById)
- {
- var propertyId = this.childrenById[fieldId].propertyId;
- existingFieldsByPropertyId[propertyId] = this.childrenById[fieldId];
- }
-
- // new data mapped by property id
- var newDataByPropertyId = {};
- for (var k in data)
- {
- if (data.hasOwnProperty(k))
- {
- newDataByPropertyId[k] = data[k];
- }
- }
-
- // walk through new property ids
- // if a field exists, set value onto it and remove from newDataByPropertyId and existingFieldsByPropertyId
- // if a field doesn't exist, let it remain in list
- for (var propertyId in newDataByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- if (field)
- {
- field.setValue(newDataByPropertyId[propertyId]);
-
- delete existingFieldsByPropertyId[propertyId];
- delete newDataByPropertyId[propertyId];
- }
- }
-
- // anything left in existingFieldsByPropertyId describes data that is missing, null or empty
- // we null out those values
- for (var propertyId in existingFieldsByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- field.setValue(null);
- }
-
- // anything left in newDataByPropertyId is new stuff that we need to add
- // the object field doesn't support this since it runs against a schema
- // so we drop this off
- },
-
- /**
- * Reconstructs the data object from the child fields.
- *
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back empty object
- if (this.children.length === 0 && !this.isRequired())
- {
- return {};
- }
-
- // otherwise, hand back an object with our child properties in it
- var o = {};
-
- // walk through all of the properties object
- // for each property, we insert it into a JSON object that we'll hand back as the result
-
- // if the property has dependencies, then we evaluate those dependencies first to determine whether the
- // resulting property should be included
-
- for (var i = 0; i < this.children.length; i++)
- {
- // the property key and vlaue
- var propertyId = this.children[i].propertyId;
- var fieldValue = this.children[i].getValue();
-
- if (typeof(fieldValue) !== "undefined")
- {
- if (this.determineAllDependenciesValid(propertyId))
- {
- var assignedValue = null;
-
- if (typeof(fieldValue) === "boolean")
- {
- assignedValue = (fieldValue? true: false);
- }
- else if (Alpaca.isArray(fieldValue) || Alpaca.isObject(fieldValue) || Alpaca.isNumber(fieldValue))
- {
- assignedValue = fieldValue;
- }
- else if (fieldValue)
- {
- assignedValue = fieldValue;
- }
-
- if (assignedValue !== null)
- {
- o[propertyId] = assignedValue;
- }
- }
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- // Generates wizard if requested
- if (self.isTopLevel())
- {
- if (self.view)
- {
- self.wizardConfigs = self.view.getWizard();
- if (typeof(self.wizardConfigs) != "undefined")
- {
- if (!self.wizardConfigs || self.wizardConfigs === true)
- {
- self.wizardConfigs = {};
- }
- }
-
- var layoutTemplateDescriptor = self.view.getLayout().templateDescriptor;
- if (self.wizardConfigs && Alpaca.isObject(self.wizardConfigs))
- {
- if (!layoutTemplateDescriptor || self.wizardConfigs.bindings)
- {
- // run the automatic wizard
- self.autoWizard();
- }
- else
- {
- // manual wizard based on layout
- self.wizard();
- }
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var _this = this;
-
- var items = [];
-
- // we keep a map of all of the properties in our original data object
- // as we render elements out of the schema, we remove from the extraDataProperties map
- // whatever is leftover are the data properties that were NOT rendered because they were not part
- // of the schema
- //
- // this is primarily maintained for debugging purposes, so as to inform the developer of mismatches
- var extraDataProperties = {};
- for (var dataKey in _this.data) {
- extraDataProperties[dataKey] = dataKey;
- }
-
- var properties = _this.data;
- if (_this.schema && _this.schema.properties) {
- properties = _this.schema.properties;
- }
-
- var cf = function()
- {
- // If the schema and the data line up perfectly, then there will be no properties in the data that are
- // not also in the schema, and thus, extraDataProperties will be empty.
- //
- // On the other hand, if there are some properties in data that were not in schema, then they will
- // remain in extraDataProperties and we can inform developers for debugging purposes
- //
- var extraDataKeys = [];
- for (var extraDataKey in extraDataProperties) {
- extraDataKeys.push(extraDataKey);
- }
- if (extraDataKeys.length > 0) {
- Alpaca.logDebug("There were " + extraDataKeys.length + " extra data keys that were not part of the schema " + JSON.stringify(extraDataKeys));
- }
-
- callback(items);
- };
-
- // each property in the object can have a different schema and options so we need to process
- // asynchronously and wait for all to complete
-
- // wrap into waterfall functions
- var propertyFunctions = [];
- for (var propertyId in properties)
- {
- var itemData = null;
- if (_this.data)
- {
- itemData = _this.data[propertyId];
- }
-
- var pf = (function(propertyId, itemData, extraDataProperties)
- {
- return function(callback)
- {
- // only allow this if we have data, otherwise we end up with circular reference
- _this.resolvePropertySchemaOptions(propertyId, function(schema, options, circular) {
-
- // we only allow addition if the resolved schema isn't circularly referenced
- // or the schema is optional
- if (circular)
- {
- return Alpaca.throwErrorWithCallback("Circular reference detected for schema: " + schema, _this.errorCallback);
- }
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for property: " + propertyId);
- }
-
- _this.createItem(propertyId, schema, options, itemData, null, function(addedItemControl) {
-
- items.push(addedItemControl);
-
- // remove from extraDataProperties helper
- delete extraDataProperties[propertyId];
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
- });
- });
- };
-
- })(propertyId, itemData, extraDataProperties);
-
- propertyFunctions.push(pf);
- }
-
- Alpaca.series(propertyFunctions, function(err) {
- cf();
- });
- },
-
- /**
- * Creates an sub-item for this object.
- *
- * The postRenderCallback method is called upon completion.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} postRenderCallback called once the item has been added
- */
- createItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, postRenderCallback)
- {
- var self = this;
-
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(_this, err);
- },
- "notTopLevel":true,
- "render" : function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // add the property Id
- fieldControl.propertyId = propertyId;
- // setup item path
- if (self.path !== "/") {
- fieldControl.path = self.path + "/" + propertyId;
- } else {
- fieldControl.path = self.path + propertyId;
- }
- fieldControl.render(null, function() {
- cb();
- });
- },
- "postRender": function(control) {
-
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- },
-
- /**
- * Determines the schema and options to utilize for sub-objects within this object.
- *
- * @param propertyId
- * @param callback
- */
- resolvePropertySchemaOptions: function(propertyId, callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedPropertySchema, resolvedPropertyOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedPropertyOptions.readonly = true;
- }
-
- callback(resolvedPropertySchema, resolvedPropertyOptions, circular);
- };
-
- var propertySchema = null;
- if (_this.schema && _this.schema.properties && _this.schema.properties[propertyId]) {
- propertySchema = _this.schema.properties[propertyId];
- }
- var propertyOptions = {};
- if (_this.options && _this.options.fields && _this.options.fields[propertyId]) {
- propertyOptions = _this.options.fields[propertyId];
- }
-
- // handle $ref
- if (propertySchema && propertySchema["$ref"])
- {
- var referenceId = propertySchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalPropertySchema = propertySchema;
- var originalPropertyOptions = propertyOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(propertySchema, propertyOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedPropertySchema = {};
- if (originalPropertySchema) {
- Alpaca.mergeObject(resolvedPropertySchema, originalPropertySchema);
- }
- if (propertySchema)
- {
- Alpaca.mergeObject(resolvedPropertySchema, propertySchema);
- }
- // keep original id
- if (originalPropertySchema && originalPropertySchema.id) {
- resolvedPropertySchema.id = originalPropertySchema.id;
- }
- //delete resolvedPropertySchema.id;
-
- var resolvedPropertyOptions = {};
- if (originalPropertyOptions) {
- Alpaca.mergeObject(resolvedPropertyOptions, originalPropertyOptions);
- }
- if (propertyOptions)
- {
- Alpaca.mergeObject(resolvedPropertyOptions, propertyOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedPropertySchema, resolvedPropertyOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(propertySchema, propertyOptions);
- });
- }
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- var f = function(i)
- {
- if (i === model.items.length)
- {
- // done
- callback();
- return;
- }
-
- var item = model.items[i];
-
- var propertyId = item.propertyId;
-
- // HANDLE PROPERTY DEPENDENCIES (IF THE PROPERTY HAS THEM)
-
- // if this property has dependencies, show or hide this added item right away
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- // if this property has dependencies, bind update handlers to dependent fields
- self.bindDependencyFieldUpdateEvent(propertyId);
-
- // if this property has dependencies, trigger those to ensure it is in the right state
- self.refreshDependentFieldStates(propertyId);
-
- f(i+1);
- };
- f(0);
- });
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxProperties();
- valInfo["tooManyProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyProperties"), [this.schema.maxProperties]),
- "status": status
- };
-
- status = this._validateMinProperties();
- valInfo["tooFewProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.minProperties]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyProperties"]["status"] && valInfo["tooFewProperties"]["status"];
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMaxProperties: function()
- {
- if (typeof(this.schema["maxProperties"]) == "undefined")
- {
- return true;
- }
-
- var maxProperties = this.schema["maxProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount <= maxProperties;
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMinProperties: function()
- {
- if (typeof(this.schema["minProperties"]) == "undefined")
- {
- return true;
- }
-
- var minProperties = this.schema["minProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount >= minProperties;
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DEPENDENCIES
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Shows or hides a property's field based on how its dependencies evaluate.
- * If a property doesn't have dependencies, this no-ops.
- *
- * @param propertyId
- */
- showOrHidePropertyBasedOnDependencies: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var valid = this.determineAllDependenciesValid(propertyId);
- if (valid)
- {
- item.show();
- item.onDependentReveal();
- }
- else
- {
- item.hide();
- item.onDependentConceal();
- }
-
- item.getFieldEl().trigger("fieldupdate");
- },
-
- /**
- * Determines whether the dependencies for a property pass.
- *
- * @param propertyId
- */
- determineAllDependenciesValid: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so yes, we pass
- return true;
- }
-
- var valid = true;
- if (Alpaca.isString(itemDependencies))
- {
- valid = self.determineSingleDependencyValid(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- valid = valid && self.determineSingleDependencyValid(propertyId, value);
- });
- }
-
- return valid;
- },
-
- /**
- * Binds field updates to any field dependencies.
- *
- * @param propertyId
- */
- bindDependencyFieldUpdateEvent: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var bindEvent = function(propertyId, dependencyPropertyId)
- {
- // dependencyPropertyId is the identifier for the property that the field "propertyId" is dependent on
-
- var dependentField = Alpaca.resolveField(self, dependencyPropertyId);
- if (dependentField)
- {
- dependentField.getFieldEl().bind("fieldupdate", (function(propertyField, dependencyField, propertyId, dependencyPropertyId) {
-
- return function(event)
- {
- // the property "dependencyPropertyId" changed and affects target property ("propertyId")
-
- // update UI state for target property
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- propertyField.getFieldEl().trigger("fieldupdate");
- };
-
- })(item, dependentField, propertyId, dependencyPropertyId));
-
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- bindEvent(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- bindEvent(propertyId, value);
- });
- }
- },
-
- refreshDependentFieldStates: function(propertyId)
- {
- var self = this;
-
- var propertyField = this.childrenByPropertyId[propertyId];
- if (!propertyField)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = propertyField.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var triggerFieldUpdateForProperty = function(otherPropertyId)
- {
- var dependentField = Alpaca.resolveField(self, otherPropertyId);
- if (dependentField)
- {
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- triggerFieldUpdateForProperty(itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- triggerFieldUpdateForProperty(value);
- });
- }
- },
-
- /**
- * Checks whether a single property's dependency is satisfied or not.
- *
- * In order to be valid, the property's dependency must exist (JSON schema) and optionally must satisfy
- * any dependency options (value matches using an AND). Finally, the dependency field must be showing.
- *
- * @param {Object} propertyId Field property id.
- * @param {Object} dependentOnPropertyId Property id of the dependency field.
- *
- * @returns {Boolean} True if all dependencies have been satisfied and the field needs to be shown,
- * false otherwise.
- */
- determineSingleDependencyValid: function(propertyId, dependentOnPropertyId)
- {
- var self = this;
-
- // checks to see if the referenced "dependent-on" property has a value
- // basic JSON-schema supports this (if it has ANY value, it is considered valid
- // special consideration for boolean false
- var dependentOnField = Alpaca.resolveField(self, dependentOnPropertyId);
- if (!dependentOnField)
- {
- // no dependent-on field found, return false
- return false;
- }
-
- var dependentOnData = dependentOnField.data;
-
- // assume it isn't valid
- var valid = false;
-
- // go one of two directions depending on whether we have conditional dependencies or not
- var conditionalDependencies = this.childrenByPropertyId[propertyId].options.dependencies;
- if (!conditionalDependencies || conditionalDependencies.length === 0)
- {
- //
- // BASIC DEPENENDENCY CHECKING (CORE JSON SCHEMA)
- //
-
- // special case: if the field is a boolean field and we have no conditional dependency checking,
- // then we set valid = false if the field data is a boolean false
- if (dependentOnField.getType() === "boolean" && !this.childrenByPropertyId[propertyId].options.dependencies && !dependentOnData)
- {
- valid = false;
- }
- else
- {
- valid = !Alpaca.isValEmpty(dependentOnField.data);
- }
- }
- else
- {
- //
- // CONDITIONAL DEPENDENCY CHECKING (ALPACA EXTENSION VIA OPTIONS)
- //
-
- // Alpaca extends JSON schema by allowing dependencies to trigger only for specific values on the
- // dependent fields. If options are specified to define this, we walk through and perform an
- // AND operation across any fields
-
- // do some data sanity cleanup
- if (dependentOnField.getType() === "boolean" && !dependentOnData) {
- dependentOnData = false;
- }
-
- var conditionalData = conditionalDependencies[dependentOnPropertyId];
-
- // if the option is a function, then evaluate the function to determine whether to show
- // the function evaluates regardless of whether the schema-based fallback determined we should show
- if (!Alpaca.isEmpty(conditionalData) && Alpaca.isFunction(conditionalData))
- {
- valid = conditionalData.call(this, dependentOnData);
- }
- else
- {
- // assume true
- valid = true;
-
- // the conditional data is an array of values
- if (Alpaca.isArray(conditionalData)) {
-
- // check array value
- //if (conditionalDependencies[dependentOnPropertyId] && $.inArray(dependentOnData, conditionalDependencies[dependentOnPropertyId]) == -1)
- if (Alpaca.anyEquality(dependentOnData, conditionalData))
- {
- valid = false;
- }
- }
- else
- {
- // check object value
- if (!Alpaca.isEmpty(conditionalData) && !Alpaca.anyEquality(conditionalData, dependentOnData))
- {
- valid = false;
- }
- }
- }
- }
-
- //
- // NESTED HIDDENS DEPENDENCY HIDES (ALPACA EXTENSION)
- //
-
- // final check: only set valid if the dependentOnPropertyId is showing
- if (dependentOnField && dependentOnField.isHidden())
- {
- valid = false;
- }
-
- return valid;
- },
-
- /**
- * Gets child index.
- *
- * @param {Object} propertyId Child field property ID.
- */
- getIndex: function(propertyId)
- {
- if (Alpaca.isEmpty(propertyId)) {
- return -1;
- }
- for (var i = 0; i < this.children.length; i++) {
- var pid = this.children[i].propertyId;
- if (pid == propertyId) { // jshint ignore:line
- return i;
- }
- }
- return -1;
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Adds an item to the object.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} callback called once the item has been added
- */
- addItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, callback)
- {
- var self = this;
-
- this.createItem(propertyId, itemSchema, itemOptions, itemData, insertAfterId, function(child) {
-
- var index = null;
- if (insertAfterId && self.childrenById[insertAfterId])
- {
- for (var z = 0; z < self.children.length; z++)
- {
- if (self.children[z].getId() == insertAfterId)
- {
- index = z;
- break;
- }
- }
- }
-
- // register the child
- self.registerChild(child, ((index != null) ? index + 1 : null));
-
- // insert into dom
- if (!index)
- {
- // insert first into container
- $(self.container).append(child.getFieldEl());
- }
- else
- {
- // insert at a specific index
- var existingElement = self.getContainerEl().children("[data-alpaca-container-item-index='" + index + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(child.getFieldEl());
- }
- }
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- //self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState(true, function() {
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
-
- });
- });
- },
-
- /**
- * Removes an item from the object.
- *
- * @param propertyId
- * @param callback
- */
- removeItem: function(propertyId, callback)
- {
- var self = this;
-
- this.children = $.grep(this.children, function(val, index) {
- return (val.getId() != propertyId);
- });
-
- var childField = this.childrenById[propertyId];
-
- delete this.childrenById[propertyId];
- if (childField.propertyId)
- {
- delete this.childrenByPropertyId[childField.propertyId];
- }
-
- childField.destroy();
-
- this.refreshValidationState(true, function() {
-
- // trigger update handler
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // WIZARD
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Wraps the current object into a wizard container and wires up the navigation and buttons so that
- * wizard elements flip nicely.
- */
- wizard: function()
- {
- var self = this;
-
- // config-driven
- var stepDescriptors = this.wizardConfigs.steps;
- if (!stepDescriptors)
- {
- stepDescriptors = [];
- }
- var wizardTitle = this.wizardConfigs.title;
- var wizardDescription = this.wizardConfigs.description;
- var buttonDescriptors = this.wizardConfigs.buttons;
- if (!buttonDescriptors)
- {
- buttonDescriptors = {};
- }
- if (!buttonDescriptors["previous"])
- {
- buttonDescriptors["previous"] = {}
- }
- if (!buttonDescriptors["previous"].title)
- {
- buttonDescriptors["previous"].title = "Previous";
- }
- if (!buttonDescriptors["previous"].align)
- {
- buttonDescriptors["previous"].align = "left";
- }
- if (!buttonDescriptors["previous"].type)
- {
- buttonDescriptors["previous"].type = "button";
- }
- if (!buttonDescriptors["next"])
- {
- buttonDescriptors["next"] = {}
- }
- if (!buttonDescriptors["next"].title)
- {
- buttonDescriptors["next"].title = "Next";
- }
- if (!buttonDescriptors["next"].align)
- {
- buttonDescriptors["next"].align = "right";
- }
- if (!buttonDescriptors["next"].type)
- {
- buttonDescriptors["next"].type = "button";
- }
-
- if (!this.wizardConfigs.hideSubmitButton)
- {
- if (!buttonDescriptors["submit"]) {
- buttonDescriptors["submit"] = {}
- }
- if (!buttonDescriptors["submit"].title) {
- buttonDescriptors["submit"].title = "Submit";
- }
- if (!buttonDescriptors["submit"].align) {
- buttonDescriptors["submit"].align = "right";
- }
- if (!buttonDescriptors["submit"].type) {
- buttonDescriptors["submit"].type = "button";
- }
- }
-
- for (var buttonKey in buttonDescriptors)
- {
- if (!buttonDescriptors[buttonKey].type)
- {
- buttonDescriptors[buttonKey].type = "button";
- }
- }
- var showSteps = this.wizardConfigs.showSteps;
- if (typeof(showSteps) == "undefined")
- {
- showSteps = true;
- }
- var showProgressBar = this.wizardConfigs.showProgressBar;
- var performValidation = this.wizardConfigs.validation;
- if (typeof(performValidation) == "undefined")
- {
- performValidation = true;
- }
-
- // DOM-driven configuration
- var wizardTitle = $(this.field).attr("data-alpaca-wizard-title");
- var wizardDescription = $(this.field).attr("data-alpaca-wizard-description");
- var _wizardValidation = $(this.field).attr("data-alpaca-wizard-validation");
- if (typeof(_wizardValidation) != "undefined")
- {
- performValidation = _wizardValidation ? true : false;
- }
- var _wizardShowSteps = $(this.field).attr("data-alpaca-wizard-show-steps");
- if (typeof(_wizardShowSteps) != "undefined")
- {
- showSteps = _wizardShowSteps ? true : false;
- }
- var _wizardShowProgressBar = $(this.field).attr("data-alpaca-wizard-show-progress-bar");
- if (typeof(_wizardShowProgressBar) != "undefined")
- {
- showProgressBar = _wizardShowProgressBar ? true : false;
- }
-
- // find all of the steps
- var stepEls = $(this.field).find("[data-alpaca-wizard-role='step']");
-
- // DOM-driven configuration of step descriptors
- if (stepDescriptors.length == 0)
- {
- stepEls.each(function(i) {
-
- var stepDescriptor = {};
-
- var stepTitle = $(this).attr("data-alpaca-wizard-step-title");
- if (typeof(stepTitle) != "undefined")
- {
- stepDescriptor.title = stepTitle;
- }
- if (!stepDescriptor.title)
- {
- stepDescriptor.title = "Step " + i;
- }
-
- var stepDescription = $(this).attr("data-alpaca-wizard-step-description");
- if (typeof(stepDescription) != "undefined")
- {
- stepDescriptor.description = stepDescription;
- }
- if (!stepDescriptor.description)
- {
- stepDescriptor.description = "Step " + i;
- }
-
- stepDescriptors.push(stepDescriptor);
- });
- }
-
- // assume something for progress bar if not specified
- if (typeof(showProgressBar) == "undefined")
- {
- if (stepDescriptors.length > 1)
- {
- showProgressBar = true;
- }
- }
-
-
- // model for use in rendering the wizard
- var model = {};
- model.wizardTitle = wizardTitle;
- model.wizardDescription = wizardDescription;
- model.showSteps = showSteps;
- model.performValidation = performValidation;
- model.steps = stepDescriptors;
- model.buttons = buttonDescriptors;
- model.schema = self.schema;
- model.options = self.options;
- model.data = self.data;
- model.showProgressBar = showProgressBar;
- model.markAllStepsVisited = this.wizardConfigs.markAllStepsVisited;
- model.view = self.view;
-
- // render the actual wizard
- var wizardTemplateDescriptor = self.view.getTemplateDescriptor("wizard", self);
- if (wizardTemplateDescriptor)
- {
- var wizardEl = Alpaca.tmpl(wizardTemplateDescriptor, model);
-
- $(self.field).append(wizardEl);
-
- var wizardNav = $(wizardEl).find(".alpaca-wizard-nav");
- var wizardSteps = $(wizardEl).find(".alpaca-wizard-steps");
- var wizardButtons = $(wizardEl).find(".alpaca-wizard-buttons");
- var wizardProgressBar = $(wizardEl).find(".alpaca-wizard-progress-bar");
-
- // move steps into place
- $(wizardSteps).append(stepEls);
-
- (function(wizardNav, wizardSteps, wizardButtons, model) {
-
- var currentIndex = 0;
-
- var previousButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='previous']");
- var nextButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='next']");
- var submitButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='submit']");
-
- // snap into place a little controller to work the buttons
- // assume the first step
- var refreshSteps = function()
- {
- // NAV
- if (model.showSteps)
- {
- if (!model.visits)
- {
- model.visits = {};
- }
-
- // optionally mark all steps as visited
- if (model.markAllStepsVisited)
- {
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- for (var g = 0; g < stepElements.length; g++)
- {
- model.visits[g] = true;
- }
- }
-
- // mark current step as visited
- model.visits[currentIndex] = true;
-
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- $(stepElements).removeClass("disabled");
- $(stepElements).removeClass("completed");
- $(stepElements).removeClass("active");
- $(stepElements).removeClass("visited");
- for (var g = 0; g < stepElements.length; g++)
- {
- if (g < currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("completed");
- }
- else if (g === currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("active");
- }
- else
- {
- if (model.visits && model.visits[g])
- {
- // do not mark disabled for this case
- }
- else
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("disabled");
- }
-
- }
-
- if (model.visits && model.visits[g])
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("visited");
- }
- }
- }
-
- // PROGRESS BAR
- if (model.showProgressBar)
- {
- var valueNow = currentIndex + 1;
- var valueMax = model.steps.length + 1;
- var width = parseInt(((valueNow / valueMax) * 100), 10) + "%";
-
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuemax", valueMax);
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuenow", valueNow);
- $(wizardProgressBar).find(".progress-bar").css("width", width);
- }
-
-
- // BUTTONS
-
- // hide everything
- previousButtonEl.hide();
- nextButtonEl.hide();
- submitButtonEl.hide();
-
- // simple case
- if (model.steps.length == 1)
- {
- submitButtonEl.show();
- }
- else if (model.steps.length > 1)
- {
- if (currentIndex > 0)
- {
- previousButtonEl.show();
- }
-
- nextButtonEl.show();
-
- if (currentIndex == 0)
- {
- nextButtonEl.show();
- }
- else if (currentIndex == model.steps.length - 1)
- {
- nextButtonEl.hide();
- submitButtonEl.show();
- }
- }
-
- // hide all steps
- $(wizardSteps).find("[data-alpaca-wizard-role='step']").hide();
- $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]).show();
-
- };
-
- var assertValidation = function(buttonId, callback)
- {
- if (!model.performValidation)
- {
- callback(true);
- return;
- }
-
- // collect all of the fields on the current step
- var fields = [];
-
- var currentStepEl = $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]);
- $(currentStepEl).find(".alpaca-field").each(function() {
- var fieldId = $(this).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var field = self.childrenById[fieldId];
- if (field)
- {
- fields.push(field);
- }
- }
- });
-
- // wrap into validation functions
- var fns = [];
- for (var i = 0; i < fields.length; i++)
- {
- fns.push(function(field) {
- return function(cb)
- {
- field.refreshValidationState(true, function() {
- cb();
- });
- }
- }(fields[i]));
- }
-
- // run all validations
- Alpaca.series(fns, function() {
-
- var valid = true;
- for (var i = 0; i < fields.length; i++)
- {
- valid = valid && fields[i].isValid(true);
- }
-
- // custom validation function?
- var b = model.buttons[buttonId];
- if (b && b.validate)
- {
- b.validate.call(self, function(_valid) {
- valid = valid && _valid;
- callback(valid);
- });
- }
- else
- {
- callback(valid);
- }
- });
- };
-
- $(previousButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex >= 1)
- {
- //assertValidation("previous", function(valid) {
-
- //if (valid)
- //{
- var b = model.buttons["previous"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex--;
-
- refreshSteps();
- //}
- //});
- }
- });
-
- $(nextButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex + 1 <= model.steps.length - 1)
- {
- assertValidation("next", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["next"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex++;
-
- refreshSteps();
- }
- });
- }
- });
-
- $(submitButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex === model.steps.length - 1)
- {
- assertValidation("submit", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["submit"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- else
- {
- // are we in a form?
- if (self.form)
- {
- self.form.submit();
- }
- }
- }
- }
- });
- }
- });
-
- // all custom buttons
- $(wizardButtons).find("[data-alpaca-wizard-button-key]").each(function() {
- var key = $(this).attr("data-alpaca-wizard-button-key");
- if (key != "submit" && key != "next" && key != "previous") { // standard buttons have different behavior
- var b = model.buttons[key];
- if (b && b.click) {
- $(this).click(function (b) {
- return function (e) {
- b.click.call(self, e);
- };
- }(b));
- }
- }
- });
-
- $(wizardNav).find("[data-alpaca-wizard-step-index]").click(function(e) {
- e.preventDefault();
-
- var navIndex = $(this).attr("data-alpaca-wizard-step-index");
- if (navIndex)
- {
- navIndex = parseInt(navIndex, 10);
-
- if (navIndex == currentIndex || (model.visits && model.visits[navIndex]))
- {
- // if we're going backwards, then we do not run validation
- if (navIndex < currentIndex)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- else if (navIndex > currentIndex)
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- });
- }
- else
- {
- // current item should not be clickable
- }
- }
- }
- });
-
- self.on("moveToStep", function(event) {
-
- var index = event.index;
- var skipValidation = event.skipValidation;
-
- if ((typeof(index) !== "undefined") && index <= model.steps.length - 1)
- {
- if (skipValidation)
- {
- currentIndex = index;
- refreshSteps();
- }
- else
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = index;
-
- refreshSteps();
- }
- });
- }
- }
- });
-
- self.on("advanceOrSubmit", function(event) {
-
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- if (currentIndex === model.steps.length - 1)
- {
- $(submitButtonEl).click();
- }
- else
- {
- $(nextButtonEl).click();
- }
- }
- });
- });
-
-
- refreshSteps();
-
- }(wizardNav, wizardSteps, wizardButtons, model));
- }
- },
-
- /**
- * Renders a configuration-based wizard without a layout template.
- */
- autoWizard: function()
- {
- var stepBindings = this.wizardConfigs.bindings;
- if (!stepBindings)
- {
- stepBindings = {};
- }
-
- for (var propertyId in this.childrenByPropertyId)
- {
- if (!stepBindings.hasOwnProperty(propertyId))
- {
- stepBindings[propertyId] = 1;
- }
- }
-
- // should we create steps?
- var createSteps = true;
- if ($(this.field).find("[data-alpaca-wizard-role='step']").length > 0)
- {
- // already there
- createSteps = false;
- }
-
- var step = 1;
- var col = [];
- do
- {
- // collect fields in this step
- col = [];
- for (var propertyId in stepBindings)
- {
- if (stepBindings[propertyId] == step)
- {
- if (this.childrenByPropertyId && this.childrenByPropertyId[propertyId])
- {
- col.push(this.childrenByPropertyId[propertyId].field);
- }
- }
- }
-
- if (col.length > 0)
- {
- var stepEl = null;
- if (createSteps)
- {
- stepEl = $('');
- $(this.field).append(stepEl);
- }
- else
- {
- stepEl = $($(this.field).find("[data-alpaca-wizard-role='step']")[step-1]);
- }
-
- // move elements in
- for (var i = 0; i < col.length; i++)
- {
- $(stepEl).append(col[i]);
- }
-
- step++;
- }
- }
- while (col.length > 0);
-
- // now run the normal wizard
- this.wizard();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "object";
- },
-
- /**
- * Moves a field.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to which the child should be moved
- * @param [Boolean] animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + sourceIndex + "']");
- var targetContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + targetIndex + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find("[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find("[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- if (animate)
- {
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, 500, function() {
- onComplete();
- });
- }
- else
- {
- onComplete();
- }
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Object Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Object field for containing other fields";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "properties": {
- "title": "Properties",
- "description": "List of child properties.",
- "type": "object"
- },
- "maxProperties": {
- "type": "number",
- "title": "Maximum Number Properties",
- "description": "The maximum number of properties that this object is allowed to have"
- },
- "minProperties": {
- "type": "number",
- "title": "Minimum Number of Properties",
- "description": "The minimum number of properties that this object is required to have"
- }
- }
- };
-
- var fieldsProperties = properties.properties.properties;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfSchema();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = Alpaca.merge(this.base(), {
- "properties": {
- }
- });
-
- var properties = {
- "properties": {
- "fields": {
- "title": "Field Options",
- "description": "List of options for child fields.",
- "type": "object"
- }
- }
- };
-
- var fieldsProperties = properties.properties.fields;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfOptions();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(schemaOfOptions, properties);
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "tooManyProperties": "The maximum number of properties ({0}) has been exceeded.",
- "tooFewProperties": "There are not enough properties ({0} are required)"
- });
-
- Alpaca.registerFieldClass("object", Alpaca.Fields.ObjectField);
- Alpaca.registerDefaultSchemaFieldMapping("object", "object");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AnyField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.AnyField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "any";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.control.disabled = true;
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.control.disabled = false;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- this.control.focus();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "any";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Any Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Any field.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("any", Alpaca.Fields.AnyField);
- Alpaca.registerDefaultSchemaFieldMapping("any", "any");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.HiddenField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ControlField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "hidden";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value)) {
- this.getControlEl().val("");
- } else {
- this.getControlEl().val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Hidden";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Field for a hidden HTML input";
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("hidden", Alpaca.Fields.HiddenField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AddressField = Alpaca.Fields.ObjectField.extend(
- /**
- * @lends Alpaca.Fields.AddressField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.ObjectField#getFieldType
- */
- getFieldType: function() {
- return "address";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.data === undefined) {
- this.data = {
- street: ['', '']
- };
- }
-
- this.schema = {
- "title": "Home Address",
- "type": "object",
- "properties": {
- "street": {
- "title": "Street",
- "type": "array",
- "items": {
- "type": "string",
- "maxLength": 30,
- "minItems": 0,
- "maxItems": 3
- }
- },
- "city": {
- "title": "City",
- "type": "string"
- },
- "state": {
- "title": "State",
- "type": "string",
- "enum": ["AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY"]
- },
- "zip": {
- "title": "Zip Code",
- "type": "string",
- "pattern": /^(\d{5}(-\d{4})?)?$/
- }
- }
- };
- Alpaca.merge(this.options, {
- "fields": {
- "zip": {
- "maskString": "99999",
- "size": 5
- },
- "state": {
- "optionLabels": ["ALABAMA", "ALASKA", "AMERICANSAMOA", "ARIZONA", "ARKANSAS", "CALIFORNIA", "COLORADO", "CONNECTICUT", "DELAWARE", "DISTRICTOFCOLUMBIA", "FEDERATEDSTATESOFMICRONESIA", "FLORIDA", "GEORGIA", "GUAM", "HAWAII", "IDAHO", "ILLINOIS", "INDIANA", "IOWA", "KANSAS", "KENTUCKY", "LOUISIANA", "MAINE", "MARSHALLISLANDS", "MARYLAND", "MASSACHUSETTS", "MICHIGAN", "MINNESOTA", "MISSISSIPPI", "MISSOURI", "MONTANA", "NEBRASKA", "NEVADA", "NEWHAMPSHIRE", "NEWJERSEY", "NEWMEXICO", "NEWYORK", "NORTHCAROLINA", "NORTHDAKOTA", "NORTHERNMARIANAISLANDS", "OHIO", "OKLAHOMA", "OREGON", "PALAU", "PENNSYLVANIA", "PUERTORICO", "RHODEISLAND", "SOUTHCAROLINA", "SOUTHDAKOTA", "TENNESSEE", "TEXAS", "UTAH", "VERMONT", "VIRGINISLANDS", "VIRGINIA", "WASHINGTON", "WESTVIRGINIA", "WISCONSIN", "WYOMING"]
- }
- }
- });
-
- if (Alpaca.isEmpty(this.options.addressValidation))
- {
- this.options.addressValidation = true;
- }
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return false;
- },
-
- /**
- * Returns address in a single line string.
- *
- * @returns {String} Address as a single line string.
- */
- getAddress: function()
- {
- var value = this.getValue();
- if (this.view.type === "view")
- {
- value = this.data;
- }
- var address = "";
- if (value)
- {
- if (value.street)
- {
- $.each(value.street, function(index, value) {
- address += value + " ";
- });
- }
- if (value.city)
- {
- address += value.city + " ";
- }
- if (value.state)
- {
- address += value.state + " ";
- }
- if (value.zip)
- {
- address += value.zip;
- }
- }
-
- return address;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
- var container = self.getContainerEl();
-
- // apply additional css
- $(container).addClass("alpaca-addressfield");
-
- if (self.options.addressValidation && !self.isDisplayOnly())
- {
- $('').appendTo(container);
- var mapButton = $(' ').appendTo(container);
- if (mapButton.button)
- {
- mapButton.button({
- text: true
- });
- }
- mapButton.click(function() {
-
- if (google && google.maps)
- {
- var geocoder = new google.maps.Geocoder();
- var address = self.getAddress();
- if (geocoder)
- {
- geocoder.geocode({
- 'address': address
- }, function(results, status)
- {
- if (status === google.maps.GeocoderStatus.OK)
- {
- var mapCanvasId = self.getId() + "-map-canvas";
- if ($('#' + mapCanvasId).length === 0)
- {
- $("").appendTo(self.getFieldEl());
- }
-
- var map = new google.maps.Map(document.getElementById(self.getId() + "-map-canvas"), {
- "zoom": 10,
- "center": results[0].geometry.location,
- "mapTypeId": google.maps.MapTypeId.ROADMAP
- });
-
- var marker = new google.maps.Marker({
- map: map,
- position: results[0].geometry.location
- });
-
- }
- else
- {
- self.displayMessage("Geocoding failed: " + status);
- }
- });
- }
-
- }
- else
- {
- self.displayMessage("Google Map API is not installed.");
- }
- }).wrap('');
-
- if (self.options.showMapOnLoad)
- {
- mapButton.click();
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getType
- */
- getType: function() {
- return "any";
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.ObjectField#getTitle
- */
- getTitle: function() {
- return "Address";
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getDescription
- */
- getDescription: function() {
- return "Standard US Address with Street, City, State and Zip. Also comes with support for Google map.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "validateAddress": {
- "title": "Address Validation",
- "description": "Enable address validation if true",
- "type": "boolean",
- "default": true
- },
- "showMapOnLoad": {
- "title": "Whether to show the map when first loaded",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "validateAddress": {
- "helper": "Address validation if checked",
- "rightLabel": "Enable Google Map for address validation?",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("address", Alpaca.Fields.AddressField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CKEditorField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.CKEditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "ckeditor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- if (!this.data)
- {
- this.data = "";
- }
-
- this.base();
-
- if (typeof(this.options.ckeditor) == "undefined")
- {
- this.options.ckeditor = {};
- }
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // see if we can render CK Editor
- if (!self.isDisplayOnly() && self.control && typeof(CKEDITOR) !== "undefined")
- {
- // use a timeout because CKEditor has some odd timing dependencies
- setTimeout(function() {
-
- self.editor = CKEDITOR.replace($(self.control)[0], self.options.ckeditor);
-
- }, 250);
- }
-
- // if the ckeditor's dom element gets destroyed, make sure we clean up the editor instance
- $(self.control).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.removeAllListeners();
- self.editor.destroy(false);
- self.editor = null;
- }
-
- });
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the plugin instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- }
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- ,
- getTitle: function() {
- return "CK Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Provides an instance of a CK Editor control for use in editing HTML.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "ckeditor": {
- "title": "CK Editor options",
- "description": "Use this entry to provide configuration options to the underlying CKEditor plugin.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "ckeditor": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("ckeditor", Alpaca.Fields.CKEditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ColorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ColorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "color";
- this.inputType = "color";
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "color";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Color Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A color picker for selecting hexadecimal color values";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("color", Alpaca.Fields.ColorField);
- Alpaca.registerDefaultSchemaFieldMapping("color", "color");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CountryField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.CountryField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "country";
- },
-
- /**
- * @see Alpaca.Fields.Field#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize))
- {
- this.options.capitalize = false;
- }
-
- this.schema["enum"] = [];
- this.options.optionLabels = [];
-
- var countriesMap = this.view.getMessage("countries");
- if (countriesMap)
- {
- for (var countryKey in countriesMap)
- {
- this.schema["enum"].push(countryKey);
-
- var label = countriesMap[countryKey];
- if (this.options.capitalize)
- {
- label = label.toUpperCase();
- }
-
- this.options.optionLabels.push(label);
- }
- }
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Country Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of countries keyed by their ISO3 code. The names of the countries are read from the I18N bundle for the current locale.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "capitalize": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("country", Alpaca.Fields.CountryField);
- Alpaca.registerDefaultFormatFieldMapping("country", "country");
-
-})(jQuery);
-
-(function($) {
-
- var round = (function() {
- var strategies = {
- up: Math.ceil,
- down: function(input) { return ~~input; },
- nearest: Math.round
- };
- return function(strategy) {
- return strategies[strategy];
- };
- })();
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CurrencyField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.CurrencyField.prototype
- */
- {
- /**
- * @constructs
- * @augments Alpaca.Fields.TextField
- *
- * @class Currency Control
- *
- * @param {Object} container Field container.
- * @param {Any} data Field data.
- * @param {Object} options Field options.
- * @param {Object} schema Field schema.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(container, data, options, schema, view, connector, errorCallback) {
- options = options || {};
-
- var pfOptionsSchema = this.getSchemaOfPriceFormatOptions().properties;
- for (var i in pfOptionsSchema) {
- var option = pfOptionsSchema[i];
- if (!(i in options)) {
- options[i] = option["default"] || undefined;
- }
- }
-
- if (typeof(data) !== "undefined")
- {
- data = "" + parseFloat(data).toFixed(options.centsLimit);
- }
-
- this.base(container, data, options, schema, view, connector, errorCallback);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "currency";
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- var field = this.getControlEl();
-
- this.base(model, function() {
-
- $(field).priceFormat(self.options);
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function() {
-
- var field = this.getControlEl();
-
- var val = $(field).is('input') ? field.val() : field.hmtl();
- if (this.options.unmask || this.options.round !== "none") {
- var unmasked = function() {
- var result = '';
- for (var i in val) {
- var cur = val[i];
- if (!isNaN(cur)) {
- result += cur;
- } else if (cur === this.options.centsSeparator) {
- result += '.';
- }
- }
- return parseFloat(result);
- }.bind(this)();
- if (this.options.round !== "none") {
- unmasked = round(this.options.round)(unmasked);
- if (!this.options.unmask) {
- var result = [];
- var unmaskedString = "" + unmasked;
- for (var i = 0, u = 0; i < val.length; i++) {
- if (!isNaN(val[i])) {
- result.push(unmaskedString[u++] || 0);
- } else {
- result.push(val[i]);
- }
- }
- return result.join('');
- }
- }
- return unmasked;
- } else {
- return val;
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Currency Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides an automatically formatted and configurable input for entering currency amounts.";
- },
-
- getSchemaOfPriceFormatOptions: function() {
- return {
- "properties": {
- "allowNegative": {
- "title": "Allow Negative",
- "description": "Determines if negative numbers are allowed.",
- "type": "boolean",
- "default": false
- },
- "centsLimit": {
- "title": "Cents Limit",
- "description": "The limit of fractional digits.",
- "type": "number",
- "default": 2,
- "minimum": 0
- },
- "centsSeparator": {
- "title": "Cents Separator",
- "description": "The separator between whole and fractional amounts.",
- "type": "text",
- "default": "."
- },
- "clearPrefix": {
- "title": "Clear Prefix",
- "description": "Determines if the prefix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "clearSuffix": {
- "title": "Clear Suffix",
- "description": "Determines if the suffix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "insertPlusSign": {
- "title": "Plus Sign",
- "description": "Determines if a plus sign should be inserted for positive values.",
- "type": "boolean",
- "default": false
- },
- "limit": {
- "title": "Limit",
- "description": "A limit of the length of the field.",
- "type": "number",
- "default": undefined,
- "minimum": 0
- },
- "prefix": {
- "title": "Prefix",
- "description": "The prefix if any for the field.",
- "type": "text",
- "default": "$"
- },
- "round": {
- "title": "Round",
- "description": "Determines if the field is rounded. (Rounding is done when getValue is called and is not reflected in the UI)",
- "type": "string",
- "enum": [ "up", "down", "nearest", "none" ],
- "default": "none"
- },
- "suffix": {
- "title": "Suffix",
- "description": "The suffix if any for the field.",
- "type": "text",
- "default": ""
- },
- "thousandsSeparator": {
- "title": "Thousands Separator",
- "description": "The separator between thousands.",
- "type": "string",
- "default": ","
- },
- "unmask": {
- "title": "Unmask",
- "description": "If true then the resulting value for this field will be unmasked. That is, the resulting value will be a float instead of a string (with the prefix, suffix, etc. removed).",
- "type": "boolean",
- "default": true
- }
- }
- };
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), this.getSchemaOfPriceFormatOptions());
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "allowNegative": {
- "type": "checkbox"
- },
- "centsLimit": {
- "type": "number"
- },
- "centsSeparator": {
- "type": "text"
- },
- "clearPrefix": {
- "type": "checkbox"
- },
- "clearSuffix": {
- "type": "checkbox"
- },
- "insertPlusSign": {
- "type": "checkbox"
- },
- "limit": {
- "type": "number"
- },
- "prefix": {
- "type": "text"
- },
- "round": {
- "type": "select"
- },
- "suffix": {
- "type": "text"
- },
- "thousandsSeparator": {
- "type": "string"
- },
- "unmask": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("currency", Alpaca.Fields.CurrencyField);
-
-})(jQuery);
-
-(function($) {
-
- // NOTE: this requires bootstrap-datetimepicker.js
- // NOTE: this requires moment.js
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DateField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.DateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "date";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY";
- },
-
- getDefaultExtraFormats: function() {
- return [];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "date";
- //this.inputType = "date";
-
- this.base();
-
- if (!self.options.picker)
- {
- self.options.picker = {};
- }
-
- if (typeof(self.options.picker.useCurrent) === "undefined") {
- self.options.picker.useCurrent = false;
- }
-
- // date format
-
- if (self.options.picker.format) {
- self.options.dateFormat = self.options.picker.format;
- }
- if (!self.options.dateFormat) {
- self.options.dateFormat = self.getDefaultFormat();
- }
- if (!self.options.picker.format) {
- self.options.picker.format = self.options.dateFormat;
- }
-
- // extra formats
- if (!self.options.picker.extraFormats) {
- var extraFormats = self.getDefaultExtraFormats();
- if (extraFormats) {
- self.options.picker.extraFormats = extraFormats;
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#afterRenderControl
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- if (self.view.type !== "display")
- {
- if ($.fn.datetimepicker)
- {
- self.getControlEl().datetimepicker(self.options.picker);
-
- self.picker = self.getControlEl().data("DateTimePicker");
- if (self.picker && self.options.dateFormat)
- {
- self.picker.format(self.options.dateFormat);
- }
- if (self.picker)
- {
- self.options.dateFormat = self.picker.format();
- }
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- getDate: function()
- {
- var self = this;
-
- var date = null;
- try
- {
- if (self.picker)
- {
- date = (self.picker.date() ? self.picker.date()._d: null);
- }
- else
- {
- date = new Date(this.getValue());
- }
- }
- catch (e)
- {
- console.error(e);
- }
-
- return date;
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- date: function()
- {
- return this.getDate();
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- this.refreshValidationState();
- },
-
- isAutoFocusable: function()
- {
- return false;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateDateFormat();
- valInfo["invalidDate"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidDate"), [this.options.dateFormat]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidDate"]["status"];
- },
-
- /**
- * Validates date format.
- *
- * @returns {Boolean} True if it is a valid date, false otherwise.
- */
- _validateDateFormat: function()
- {
- var self = this;
-
- var isValid = true;
-
- if (self.options.dateFormat)
- {
- var value = self.getValue();
- if (value || self.isRequired())
- {
- // collect all formats
- var dateFormats = [];
- dateFormats.push(self.options.dateFormat);
- if (self.options.picker && self.options.picker.extraFormats)
- {
- for (var i = 0; i < self.options.picker.extraFormats.length; i++)
- {
- dateFormats.push(self.options.picker.extraFormats[i]);
- }
- }
-
- for (var i = 0; i < dateFormats.length; i++)
- {
- isValid = isValid || moment(value, self.options.dateFormat, true).isValid();
- }
- }
- }
-
- return isValid;
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- this.base(value);
-
- if (this.picker)
- {
- if (moment(value, self.options.dateFormat, true).isValid())
- {
- this.picker.date(value);
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- return this.base();
- },
-
- destroy: function()
- {
- this.base();
-
- this.picker = null;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Date Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Date Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"date",
- "enum" : ["date"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "dateFormat": {
- "title": "Date Format",
- "description": "Date format (using moment.js format)",
- "type": "string"
- },
- "picker": {
- "title": "DatetimePicker options",
- "description": "Options that are supported by the Bootstrap DateTime Picker.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "dateFormat": {
- "type": "text"
- },
- "picker": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidDate": "Invalid date for format {0}"
- });
- Alpaca.registerFieldClass("date", Alpaca.Fields.DateField);
- Alpaca.registerDefaultFormatFieldMapping("date", "date");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DatetimeField = Alpaca.Fields.DateField.extend(
- /**
- * @lends Alpaca.Fields.DatetimeField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "datetime";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY HH:mm:ss";
- },
-
- getDefaultExtraFormats: function() {
- return [
- "MM/DD/YYYY hh:mm:ss a",
- "MM/DD/YYYY HH:mm",
- "MM/DD/YYYY"
- ];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "datetime";
- //this.inputType = "datetime";
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Datetime Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Datetime Field based on Bootstrap DateTime Picker.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("datetime", Alpaca.Fields.DatetimeField);
-
- // "datetime" is legacy (pre v4 schema)
- Alpaca.registerDefaultFormatFieldMapping("datetime", "datetime");
-
- // official v4 uses date-time
- Alpaca.registerDefaultFormatFieldMapping("date-time", "datetime");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EditorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "editor";
- },
-
- setup: function()
- {
- var self = this;
-
- this.base();
-
- if (!self.options.aceTheme)
- {
- self.options.aceTheme = "ace/theme/chrome";
- }
-
- if (!self.options.aceMode)
- {
- self.options.aceMode = "ace/mode/json";
- }
-
- if (typeof(self.options.beautify) == "undefined")
- {
- self.options.beautify = true;
- }
-
- if (self.options.beautify && this.data)
- {
- if (self.options.aceMode === "ace/mode/json")
- {
- if (Alpaca.isObject(this.data))
- {
- // convert to string to format it
- this.data = JSON.stringify(this.data, null, " ");
- }
- else if (Alpaca.isString(this.data))
- {
- // convert to object and then back to string to format it
- this.data = JSON.stringify(JSON.parse(this.data), null, " ");
- }
- }
-
- if (self.options.aceMode === "ace/mode/html")
- {
- if (typeof(html_beautify) !== "undefined")
- {
- this.data = html_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/css")
- {
- if (typeof(css_beautify) !== "undefined")
- {
- this.data = css_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/javascript")
- {
- if (typeof(js_beautify) !== "undefined")
- {
- this.data = js_beautify(this.data);
- }
- }
- }
-
- if (self.options.aceMode === "ace/mode/json")
- {
- if (!this.data || this.data === "{}")
- {
- this.data = "{\n\t\n}";
- }
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // ACE HEIGHT
- var aceHeight = self.options.aceHeight;
- if (aceHeight)
- {
- $(self.control).css("height", aceHeight);
- }
-
- // ACE WIDTH
- var aceWidth = self.options.aceWidth;
- if (!aceWidth) {
- aceWidth = "100%";
- }
- $(self.control).css("width", aceWidth);
- }
-
- // locate where we will insert the editor
- var el = $(self.control)[0];
-
- // ace must be included ahead of time
- if (!ace && window.ace) {
- ace = window.ace;
- }
-
- if (!ace)
- {
- Alpaca.logError("Editor Field is missing the 'ace' Cloud 9 Editor");
- }
- else
- {
- self.editor = ace.edit(el);
- self.editor.setOptions({
- maxLines: Infinity
- });
-
- self.editor.getSession().setUseWrapMode(true);
-
- // theme
- var aceTheme = self.options.aceTheme;
- self.editor.setTheme(aceTheme);
-
- // mode
- var aceMode = self.options.aceMode;
- self.editor.getSession().setMode(aceMode);
-
- self.editor.renderer.setHScrollBarAlwaysVisible(false);
- //this.editor.renderer.setVScrollBarAlwaysVisible(false); // not implemented
- self.editor.setShowPrintMargin(false);
-
- // set data onto editor
- self.editor.setValue(self.data);
- self.editor.clearSelection();
-
- // clear undo session
- self.editor.getSession().getUndoManager().reset();
-
- // FIT-CONTENT the height of the editor to the contents contained within
- if (self.options.aceFitContentHeight)
- {
- var heightUpdateFunction = function() {
-
- var first = false;
- if (self.editor.renderer.lineHeight === 0)
- {
- first = true;
- self.editor.renderer.lineHeight = 16;
- }
-
- // http://stackoverflow.com/questions/11584061/
- var newHeight = self.editor.getSession().getScreenLength() * self.editor.renderer.lineHeight + self.editor.renderer.scrollBar.getWidth();
-
- $(self.control).height(newHeight.toString() + "px");
-
- // This call is required for the editor to fix all of
- // its inner structure for adapting to a change in size
- self.editor.resize();
-
- if (first)
- {
- window.setTimeout(function() {
- self.editor.clearSelection();
- }, 100);
- }
- };
-
- // Set initial size to match initial content
- heightUpdateFunction();
-
- // Whenever a change happens inside the ACE editor, update
- // the size again
- self.editor.getSession().on('change', heightUpdateFunction);
- }
-
- // READONLY
- if (self.schema.readonly)
- {
- self.editor.setReadOnly(true);
- }
-
- // if the editor's dom element gets destroyed, make sure we clean up the editor instance
- // normally, we expect Alpaca fields to be destroyed by the destroy() method but they may also be
- // cleaned-up via the DOM, thus we check here.
- $(el).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.destroy();
- self.editor = null;
- }
-
- });
- }
-
- callback();
- });
-
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the editor instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- },
-
- /**
- * @return the ACE editor instance
- */
- getEditor: function()
- {
- return this.editor;
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var wordCountStatus = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": wordCountStatus ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": wordCountStatus
- };
-
- var editorAnnotationsStatus = this._validateEditorAnnotations();
- valInfo["editorAnnotationsExist"] = {
- "message": editorAnnotationsStatus ? "" : this.view.getMessage("editorAnnotationsExist"),
- "status": editorAnnotationsStatus
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"] && valInfo["editorAnnotationsExist"]["status"];
- },
-
- _validateEditorAnnotations: function()
- {
- if (this.editor)
- {
- var annotations = this.editor.getSession().getAnnotations();
- if (annotations && annotations.length > 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.editor.getValue();
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Force editor to resize to ensure it gets drawn correctly.
- * @override
- */
- onDependentReveal: function()
- {
- if (this.editor)
- {
- this.editor.resize();
- }
- },
-
- /**
- *@see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- if (this.editor)
- {
- if (self.schema.type == "object" && Alpaca.isObject(value))
- {
- // format
- value = JSON.stringify(value, null, " ");
- }
-
- this.editor.setValue(value);
- self.editor.clearSelection();
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var value = null;
-
- if (this.editor)
- {
- value = this.editor.getValue();
- }
-
- // if expected type back is "object", we do the conversion
- if (this.schema.type == "object")
- {
- if (!value)
- {
- value = {};
- }
- else
- {
- value = JSON.parse(value);
- }
- }
-
- return value;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Editor";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "aceTheme": {
- "title": "ACE Editor Theme",
- "description": "Specifies the theme to set onto the editor instance",
- "type": "string",
- "default": "ace/theme/twilight"
- },
- "aceMode": {
- "title": "ACE Editor Mode",
- "description": "Specifies the mode to set onto the editor instance",
- "type": "string",
- "default": "ace/mode/javascript"
- },
- "aceWidth": {
- "title": "ACE Editor Height",
- "description": "Specifies the width of the wrapping div around the editor",
- "type": "string",
- "default": "100%"
- },
- "aceHeight": {
- "title": "ACE Editor Height",
- "description": "Specifies the height of the wrapping div around the editor",
- "type": "string",
- "default": "300px"
- },
- "aceFitContentHeight": {
- "title": "ACE Fit Content Height",
- "description": "Configures the ACE Editor to auto-fit its height to the contents of the editor",
- "type": "boolean",
- "default": false
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "aceTheme": {
- "type": "text"
- },
- "aceMode": {
- "type": "text"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded.",
- "editorAnnotationsExist": "The editor has errors in it that must be corrected"
- });
-
- Alpaca.registerFieldClass("editor", Alpaca.Fields.EditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EmailField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EmailField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "email";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "email";
- this.inputType = "email";
-
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.email;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidEmail");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Email Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Email Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.email;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"email",
- "enum":["email"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidEmail": "Invalid Email address e.g. info@cloudcms.com"
- });
- Alpaca.registerFieldClass("email", Alpaca.Fields.EmailField);
- Alpaca.registerDefaultFormatFieldMapping("email", "email");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.GridField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.GridField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "grid";
- },
-
- setup: function()
- {
- this.base();
-
- if (typeof(this.options.grid) == "undefined")
- {
- this.options.grid = {};
- }
- },
-
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // convert the data array into the grid's expected format
- var gridData = [];
-
- // add in headers
- var headers = [];
- for (var key in self.options.fields)
- {
- var fieldDefinition = self.options.fields[key];
-
- var label = key;
- if (fieldDefinition.label)
- {
- label = fieldDefinition.label;
- }
-
- headers.push(label);
- }
- gridData.push(headers);
-
- for (var i = 0; i < self.data.length; i++)
- {
- var row = [];
- for (var key2 in self.data[i])
- {
- row.push(self.data[i][key2]);
- }
- gridData.push(row);
- }
-
- /*
- // TODO
- var gridData = [
- ["Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
- ["2009", 0, 2941, 4303, 354, 5814],
- ["2010", 5, 2905, 2867, 412, 5284],
- ["2011", 4, 2517, 4822, 552, 6127],
- ["2012", 2, 2422, 5399, 776, 4151]
- ];
- */
-
- var holder = $(self.container).find(".alpaca-container-grid-holder");
-
- var gridConfig = self.options.grid;
- gridConfig.data = gridData;
-
- $(holder).handsontable(gridConfig);
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.ControlField#getType
- */
- getType: function() {
- return "array";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.ControlField#getTitle
- */
- getTitle: function() {
- return "Grid Field";
- },
-
- /**
- * @see Alpaca.ControlField#getDescription
- */
- getDescription: function() {
- return "Renders array items into a grid";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("grid", Alpaca.Fields.GridField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ImageField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ImageField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "image";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Image Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Image Field.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("image", Alpaca.Fields.ImageField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IntegerField = Alpaca.Fields.NumberField.extend(
- /**
- * @lends Alpaca.Fields.IntegerField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.NumberField#getFieldType
- */
- getFieldType: function() {
- return "integer";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseInt(val, 10);
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- if (this.slider)
- {
- this.slider.slider("value", this.getValue());
- }
- },
-
- /**
- * @see Alpaca.Fields.NumberField#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- if (self.options.slider)
- {
- if (!Alpaca.isEmpty(self.schema.maximum) && !Alpaca.isEmpty(self.schema.minimum))
- {
- if (self.control)
- {
- self.control.after('');
-
- self.slider = $('#slider', self.control.parent()).slider({
- value: self.getValue(),
- min: self.schema.minimum,
- max: self.schema.maximum,
- slide: function(event, ui) {
- self.setValue(ui.value);
- self.refreshValidationState();
- }
- });
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Fields.NumberField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateInteger();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotAnInteger"),
- "status": status
- };
-
- return baseStatus;
- },
-
- /**
- * Validates if it is an integer.
- *
- * @returns {Boolean} true if it is an integer
- */
- _validateInteger: function()
- {
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid integer format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.integer, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getType
- */
- getType: function() {
- return "integer";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.NumberField#getTitle
- */
- getTitle: function() {
- return "Integer Field";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getDescription
- */
- getDescription: function() {
- return "Field for integers.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "integer"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "integer"
- },
- "divisibleBy": {
- "title": "Divisible By",
- "description": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "minimum": {
- "helper": "Minimum value of the field.",
- "type": "integer"
- },
- "maximum": {
- "helper": "Maximum value of the field.",
- "type": "integer"
- },
- "divisibleBy": {
- "helper": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "slider": {
- "title": "Slider",
- "description": "Generate jQuery UI slider control with the field if true.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "slider": {
- "rightLabel": "Slider control ?",
- "helper": "Generate slider control if selected.",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAnInteger": "This value is not an integer."
- });
- Alpaca.registerFieldClass("integer", Alpaca.Fields.IntegerField);
- Alpaca.registerDefaultSchemaFieldMapping("integer", "integer");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IPv4Field = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.IPv4Field.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "ipv4";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.ipv4;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"])
- {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidIPv4");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "IP Address Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "IP Address Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : Alpaca.regexps.ipv4;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "enum": ["ip-address"],
- "default":"ip-address",
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidIPv4": "Invalid IPv4 address, e.g. 192.168.0.1"
- });
- Alpaca.registerFieldClass("ipv4", Alpaca.Fields.IPv4Field);
- Alpaca.registerDefaultFormatFieldMapping("ip-address", "ipv4");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.JSONField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.JSONField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "json";
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- setValue: function(value)
- {
- if (Alpaca.isObject(value) || typeof(value) === "object")
- {
- value = JSON.stringify(value, null, 3);
- }
-
- this.base(value);
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (val && Alpaca.isString(val))
- {
- val = JSON.parse(val);
- }
-
- return val;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateJSON();
- valInfo["stringNotAJSON"] = {
- "message": status.status ? "" : this.view.getMessage("stringNotAJSON") +" "+ status.message,
- "status": status.status
- };
-
- return baseStatus && valInfo["stringNotAJSON"]["status"] ;
- },
-
- /**
- * Validates if it is a valid JSON object.
- * @returns {Boolean} true if it is a valid JSON object
- */
- _validateJSON: function()
- {
- var textValue = this.control.val();
-
- // allow null
- if (Alpaca.isValEmpty(textValue))
- {
- return {
- "status" : true
- };
- }
-
- // parse the string
- try
- {
- var obj = JSON.parse(textValue);
-
- // format the string as well
- this.setValue(JSON.stringify(obj, null, 3));
- return {
- "status" : true
- };
- }
- catch(e)
- {
- return {
- "status" : false,
- "message" : e.message
- };
- }
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // Some auto-formatting capabilities
- self.control.bind('keypress', function(e) {
-
- var code = e.keyCode || e.wich;
-
- if (code === 34) {
- self.control.insertAtCaret('"');
- }
- if (code === 123) {
- self.control.insertAtCaret('}');
- }
- if (code === 91) {
- self.control.insertAtCaret(']');
- }
- });
-
- self.control.bind('keypress', 'Ctrl+l', function() {
- self.getFieldEl().removeClass("alpaca-field-focused");
-
- // set class from state
- self.refreshValidationState();
- });
-
- self.control.attr('title','Type Ctrl+L to format and validate the JSON string.');
- }
-
- callback();
-
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "JSON Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Editor for JSON objects with basic validation and formatting.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAJSON": "This value is not a valid JSON string."
- });
-
- Alpaca.registerFieldClass("json", Alpaca.Fields.JSONField);
-
- $.fn.insertAtCaret = function (myValue) {
-
- return this.each(function() {
-
- //IE support
- if (document.selection) {
-
- this.focus();
- sel = document.selection.createRange();
- sel.text = myValue;
- this.focus();
-
- } else if (this.selectionStart || this.selectionStart == '0') { // jshint ignore:line
-
- //MOZILLA / NETSCAPE support
- var startPos = this.selectionStart;
- var endPos = this.selectionEnd;
- var scrollTop = this.scrollTop;
- this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
- this.focus();
- this.selectionStart = startPos /*+ myValue.length*/;
- this.selectionEnd = startPos /*+ myValue.length*/;
- this.scrollTop = scrollTop;
-
- } else {
-
- this.value += myValue;
- this.focus();
- }
- });
- };
-
- /*
- * jQuery Hotkeys Plugin
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- *
- * Based upon the plugin by Tzury Bar Yochay:
- * http://github.com/tzuryby/hotkeys
- *
- * Original idea by:
- * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
- */
- jQuery.hotkeys = {
- version: "0.8",
-
- specialKeys: {
- 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
- 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
- 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
- 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
- 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
- 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
- },
-
- shiftNums: {
- "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
- "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
- ".": ">", "/": "?", "\\": "|"
- }
- };
-
- function keyHandler( handleObj ) {
- // Only care when a possible input has been specified
- if ( typeof handleObj.data !== "string" ) {
- return;
- }
-
- var origHandler = handleObj.handler,
- keys = handleObj.data.toLowerCase().split(" ");
-
- handleObj.handler = function( event ) {
- // Don't fire in text-accepting inputs that we didn't directly bind to
- if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
- event.target.type === "text") ) {
- return;
- }
-
- // Keypress represents characters, not special keys
- var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
- character = String.fromCharCode( event.which ).toLowerCase(),
- key, modif = "", possible = {};
-
- // check combinations (alt|ctrl|shift+anything)
- if ( event.altKey && special !== "alt" ) {
- modif += "alt+";
- }
-
- if ( event.ctrlKey && special !== "ctrl" ) {
- modif += "ctrl+";
- }
-
- // TODO: Need to make sure this works consistently across platforms
- if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
- modif += "meta+";
- }
-
- if ( event.shiftKey && special !== "shift" ) {
- modif += "shift+";
- }
-
- if ( special ) {
- possible[ modif + special ] = true;
-
- } else {
- possible[ modif + character ] = true;
- possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
-
- // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
- if ( modif === "shift+" ) {
- possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
- }
- }
-
- for ( var i = 0, l = keys.length; i < l; i++ ) {
- if ( possible[ keys[i] ] ) {
- return origHandler.apply( this, arguments );
- }
- }
- };
- }
-
- jQuery.each([ "keydown", "keyup", "keypress" ], function() {
- jQuery.event.special[ this ] = { add: keyHandler };
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.LowerCaseField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.LowerCaseField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "lowercase";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var lowerValue = val.toLowerCase();
-
- if (lowerValue != this.getValue()) // jshint ignore:line
- {
- this.base(lowerValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Lowercase Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text field for lowercase text.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("lowercase", Alpaca.Fields.LowerCaseField);
- Alpaca.registerDefaultFormatFieldMapping("lowercase", "lowercase");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.MapField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.MapField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "map";
- },
-
- getType: function()
- {
- return "object"
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- // special handling - data can come in as an object, we convert to array
- if (this.data && Alpaca.isObject(this.data))
- {
- var newData = [];
-
- $.each(this.data, function(key, value) {
- var newValue = Alpaca.copyOf(value);
- newValue["_key"] = key;
- newData.push(newValue);
- });
-
- this.data = newData;
- }
-
- this.base();
-
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // special handling, convert back to object
- var o = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
- if (key)
- {
- delete v["_key"];
- o[key] = v;
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var isValidMapKeysNotEmpty = this._validateMapKeysNotEmpty();
- valInfo["keyMissing"] = {
- "message": isValidMapKeysNotEmpty ? "" : this.view.getMessage("keyMissing"),
- "status": isValidMapKeysNotEmpty
- };
-
- var isValidMapKeysUnique = this._validateMapKeysUnique();
- valInfo["keyNotUnique"] = {
- "message": isValidMapKeysUnique ? "" : this.view.getMessage("keyNotUnique"),
- "status": isValidMapKeysUnique
- };
-
- return baseStatus && valInfo["keyMissing"]["status"] && valInfo["keyNotUnique"]["status"];
- },
-
- /**
- * Validates that key fields are not empty.
- *
- * @returns {Boolean} true if keys are not empty
- */
- _validateMapKeysNotEmpty: function()
- {
- var isValid = true;
-
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (!key)
- {
- isValid = false;
- break;
- }
- }
-
- return isValid;
- },
-
- /**
- * Validates if key fields are unique.
- *
- * @returns {Boolean} true if keys are unique
- */
- _validateMapKeysUnique: function()
- {
- var isValid = true;
-
- var keys = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (keys[key])
- {
- isValid = false;
- }
-
- keys[key] = key;
- }
-
- return isValid;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "Map Field";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Field for objects with key/value pairs that share the same schema for values.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("map", Alpaca.Fields.MapField);
-
- // Additional Registrations
- Alpaca.registerMessages({
- "keyNotUnique": "Keys of map field are not unique.",
- "keyMissing": "Map contains an empty key."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PasswordField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PasswordField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "password";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.password;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPassword");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Password Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Password Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : /^[0-9a-zA-Z\x20-\x7E]*$/;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": this.schema.pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"password",
- "enum":["password"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPassword": "Invalid Password"
- });
- Alpaca.registerFieldClass("password", Alpaca.Fields.PasswordField);
- Alpaca.registerDefaultFormatFieldMapping("password", "password");
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PersonalNameField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PersonalNameField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "personalname";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var upperValue = "";
-
- for ( var i = 0; i < val.length; i++ )
- {
- if ( i === 0 )
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else if (val.charAt(i-1) === ' ' || val.charAt(i-1) === '-' || val.charAt(i-1) === "'")
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else
- {
- upperValue += val.charAt(i);
- }
- }
-
- if (upperValue != this.getValue()) // jshint ignore:line
- {
- this.base(upperValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Personal Name";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text Field for personal name with captical letter for first letter & after hyphen, space or apostrophe.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("personalname", Alpaca.Fields.PersonalNameField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PhoneField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PhoneField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "tel";
- this.inputType = "tel";
-
- this.base();
-
- if (!this.schema.pattern) {
- this.schema.pattern = Alpaca.regexps.phone;
- }
-
- if (Alpaca.isEmpty(this.options.maskString)) {
- this.options.maskString = "(999) 999-9999";
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPhone");
- }
-
- return baseStatus;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "phone";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Phone Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Phone Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.phone;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"phone",
- "enum":["phone"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "maskString": {
- "title": "Field Mask String",
- "description": "Expression for field mask",
- "type": "string",
- "default": "(999) 999-9999"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPhone": "Invalid Phone Number, e.g. (123) 456-9999"
- });
- Alpaca.registerFieldClass("phone", Alpaca.Fields.PhoneField);
- Alpaca.registerDefaultFormatFieldMapping("phone", "phone");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SearchField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.SearchField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "search";
- this.inputType = "search";
-
- this.base();
-
- this.options.attributes.results = 5;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "search";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Search Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A search box field";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("search", Alpaca.Fields.SearchField);
- Alpaca.registerDefaultSchemaFieldMapping("search", "search");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.usHoldings = {};
-
- Alpaca.usHoldings.territories = {
- "American Samoa" : "AS",
- "District Of Columbia" : "DC",
- "Federated States Of Micronesia" : "FM",
- "Guam" : "GU",
- "Marshall Islands" : "MH",
- "Northern Mariana Islands" : "MP",
- "Palau" : "PW",
- "Puerto Rico" : "PR",
- "Virgin Islands" : "VI"
- };
-
- Alpaca.usHoldings.states = {
- "Alabama" : "AL",
- "Alaska" : "AK",
- "Arizona" : "AZ",
- "Arkansas" : "AR",
- "California" : "CA",
- "Colorado" : "CO",
- "Connecticut" : "CT",
- "Delaware" : "DE",
- "Florida" : "FL",
- "Georgia" : "GA",
- "Hawaii" : "HI",
- "Idaho" : "ID",
- "Illinois" : "IL",
- "Indiana" : "IN",
- "Iowa" : "IA",
- "Kansas" : "KS",
- "Kentucky" : "KY",
- "Louisiana" : "LA",
- "Maine" : "ME",
- "Maryland" : "MD",
- "Massachusetts" : "MA",
- "Michigan" : "MI",
- "Minnesota" : "MN",
- "Mississippi" : "MS",
- "Missouri" : "MO",
- "Montana" : "MT",
- "Nebraska" : "NE",
- "Nevada" : "NV",
- "New Hampshire" : "NH",
- "New Jersey" : "NJ",
- "New Mexico" : "NM",
- "New York" : "NY",
- "North Carolina" : "NC",
- "North Dakota" : "ND",
- "Ohio" : "OH",
- "Oklahoma" : "OK",
- "Oregon" : "OR",
- "Pennsylvania" : "PA",
- "Rhode Island" : "RI",
- "South Carolina" : "SC",
- "South Dakota" : "SD",
- "Tennessee" : "TN",
- "Texas" : "TX",
- "Utah" : "UT",
- "Vermont" : "VT",
- "Virginia" : "VA",
- "Washington" : "WA",
- "West Virginia" : "WV",
- "Wisconsin" : "WI",
- "Wyoming" : "WY"
- };
-
- Alpaca.Fields.StateField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.StateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "state";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize)) {
- this.options.capitalize = false;
- }
- if (Alpaca.isUndefined(this.options.includeStates)) {
- this.options.includeStates = true;
- }
- if (Alpaca.isUndefined(this.options.includeTerritories)) {
- this.options.includeTerritories = true;
- }
- if (Alpaca.isUndefined(this.options.format)) {
- this.options.format = "name";
- }
-
- // validate settings
- if (this.options.format === "name" || this.options.format === "code")
- {
- // valid formats
- }
- else
- {
- Alpaca.logError("The configured state format: " + this.options.format + " is not a legal value [name, code]");
-
- // default to name format
- this.options.format = "name";
- }
-
- // configure
- var holdings = Alpaca.retrieveUSHoldings(
- this.options.includeStates,
- this.options.includeTerritories,
- (this.options.format === "code"),
- this.options.capitalize);
-
- this.schema["enum"] = holdings.keys;
- this.options.optionLabels = holdings.values;
-
- this.base();
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "State Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of states and/or territories in the United States, keyed by their two-character code.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "How to represent the state values in the selector",
- "type": "string",
- "default": "name",
- "enum":["name", "code"],
- "readonly": true
- },
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- },
- "includeStates": {
- "title": "Include States",
- "description": "Whether to include the states of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- },
- "includeTerritories": {
- "title": "Include Territories",
- "description": "Whether to include the territories of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- },
- "capitalize": {
- "type": "checkbox"
- },
- "includeStates": {
- "type": "checkbox"
- },
- "includeTerritories": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("state", Alpaca.Fields.StateField);
- Alpaca.registerDefaultFormatFieldMapping("state", "state");
-
- /**
- * Helper function to retrieve the holdings of US states and territories.
- *
- * @param {Boolean} includeStates whether to include US states
- * @param {Boolean} includeTerritories whether to include US territories
- * @param {Boolean} codeValue whether to hand back US holding codes (instead of names)
- * @param {Boolean} capitalize whether to capitalize the values handed back
- *
- * @returns {Object} an object containing "keys" and "values", both of which are arrays.
- */
- Alpaca.retrieveUSHoldings = (function()
- {
- return function(includeStates, includeTerritories, codeValue, capitalize) {
- var res = {
- keys: [],
- values: []
- };
- var opts = $.extend(
- {},
- includeStates ? Alpaca.usHoldings.states : {},
- includeTerritories ? Alpaca.usHoldings.territories : {}
- );
- var sorted = Object.keys(opts);
- sorted.sort();
- for (var i in sorted) {
- var state = sorted[i];
- var key = opts[state];
- var value = codeValue ? key : state;
- if (capitalize) {
- value = value.toUpperCase();
- }
- res.keys.push(key);
- res.values.push(value);
- }
- return res;
- };
- })();
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- /**
- * The table field is used for data representations that consist of an array with objects inside of it. The objects
- * must have a uniform structure. The table field renders a standard HTML table using the table. The individual
- * columns are either editable (in edit mode) or simply displayed in read-only mode.
- */
- Alpaca.Fields.TableField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.TableField.prototype
- */
- {
- setup: function()
- {
- var self = this;
-
- if (!self.options)
- {
- self.options = {};
- }
-
- if (typeof(self.options.animate) === "undefined")
- {
- self.options.animate = false;
- }
-
- this.base();
-
- if (!this.options.items.type)
- {
- this.options.items.type = "tablerow";
- }
-
- // support for either "datatable" or "datatables"
- if (this.options.datatable) {
- this.options.datatables = this.options.datatable;
- }
-
- // assume empty options for datatables
- if (typeof(this.options.datatables) === "undefined")
- {
- this.options.datatables = {
- "paging": false,
- "lengthChange": false,
- "info": false,
- "searching": false,
- "ordering": true
- };
- }
-
- // assume actions column to be shown
- if (typeof(this.options.showActionsColumn) === "undefined")
- {
- this.options.showActionsColumn = true;
-
- if (this.options.readonly)
- {
- this.options.showActionsColumn = false;
- }
-
- if (this.isDisplayOnly())
- {
- this.options.showActionsColumn = false;
- }
- }
- },
-
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "table";
- },
-
- /**
- * The table field uses the "array" container convention to render the DOM. As such, nested objects are wrapped
- * in "field" elements that result in slightly incorrect table structures. Part of the reason for this is that
- * browsers are very fussy when it comes to injection of nested TR or TD partials. Here, we generate most
- * things as DIVs and then do some cleanup in this method to make sure that the table is put togehter in the
- * right way.
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- self.cleanupDomInjections();
-
- // apply styles of underlying "table"
- var table = $(this.container).find("table");
- self.applyStyle("table", table);
-
- // if the DataTables plugin is available, use it
- if (self.options.datatables)
- {
- if ($.fn.DataTable)
- {
- $(this.container).find("table").DataTable(self.options.datatables);
- }
- }
-
- callback();
-
- }.bind(self));
- },
-
- cleanupDomInjections: function()
- {
- /**
- * Takes a DOM element and merges it "up" to the parent element. Data attributes and some classes are
- * copied from DOM element into the parent element. The children of the DOM element are added to the
- * parent and the DOM element is removed.
- *
- * @param mergeElement
- */
- var mergeElementUp = function(mergeElement)
- {
- var mergeElementParent = $(mergeElement).parent();
- var mergeElementChildren = $(mergeElement).children();
-
- // copy merge element classes to parent
- var classNames =$(mergeElement).attr('class').split(/\s+/);
- $.each( classNames, function(index, className){
- if (className === "alpaca-merge-up") {
- // skip
- } else {
- $(mergeElementParent).addClass(className);
- }
- });
-
- // copy attributes to TR
- $.each($(mergeElement)[0].attributes, function() {
- if (this.name && this.name.indexOf("data-") === 0)
- {
- $(mergeElementParent).attr(this.name, this.value);
- }
- });
-
- // replace field with children
- if (mergeElementChildren.length > 0)
- {
- $(mergeElement).replaceWith(mergeElementChildren);
- }
- else
- {
- $(mergeElement).remove();
- }
- };
-
- // find each TR's .alpaca-field and merge up
- this.getFieldEl().find("tr > .alpaca-field").each(function() {
- mergeElementUp(this);
- });
-
- // find each TR's .alpaca-container and merge up
- this.getFieldEl().find("tr > .alpaca-container").each(function() {
- mergeElementUp(this);
- });
-
- // find the action bar and slip a TD around it
- var alpacaArrayActionbar = this.getFieldEl().find("." + Alpaca.MARKER_CLASS_ARRAY_ITEM_ACTIONBAR);
- if (alpacaArrayActionbar.length > 0)
- {
- alpacaArrayActionbar.each(function() {
- var td = $("\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function l(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}function c(){var e="";return e}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-any"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s,l="",c=i.helperMissing;return l+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-checkbox"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s,l="",c=i.helperMissing;return l+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-image"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function",c=this.escapeExpression;return s+=''},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-radio"]=function(e,t,i,a,n){function r(e,t,a){var n,r,s,l="";return l+="\n ",r=i.compare||e&&e.compare,s={hash:{},inverse:d.noop,fn:d.program(2,o,t),data:t},n=r?r.call(e,e&&e.value,a&&a.data,s):p.call(e,"compare",e&&e.value,a&&a.data,s),(n||0===n)&&(l+=n),l+="\n "}function o(e,t){var a,n,r="";return r+="\n ",(n=i.text)?a=n.call(e,{hash:{},data:t}):(n=e&&e.text,a=typeof n===c?n.call(e,{hash:{},data:t}):n),(a||0===a)&&(r+=a),r+="\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var s,l="",c="function",d=this,p=i.helperMissing;return l+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-select"]=function(e,t,i,a,n){function r(e,t,a){var n,r,s,l="";return l+="\n ",r=i.compare||e&&e.compare,s={hash:{},inverse:d.noop,fn:d.program(2,o,t),data:t},n=r?r.call(e,e&&e.value,a&&a.data,s):p.call(e,"compare",e&&e.value,a&&a.data,s),(n||0===n)&&(l+=n),l+="\n "}function o(e,t){var a,n,r="";return r+="\n ",(n=i.text)?a=n.call(e,{hash:{},data:t}):(n=e&&e.text,a=typeof n===c?n.call(e,{hash:{},data:t}):n),(a||0===a)&&(r+=a),r+="\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var s,l="",c="function",d=this,p=i.helperMissing;return l+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-text"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-textarea"]=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"]["control-url"]=function(e,t,i,a,n){function r(e){var t,i="";return i+='target="'+f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTarget,typeof t===h?t.apply(e):t))+'"'}function o(e){var t;return f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTitle,typeof t===h?t.apply(e):t))}function s(e,t){var a,n;return(n=i.data)?a=n.call(e,{hash:{},data:t}):(n=e&&e.data,a=typeof n===h?n.call(e,{hash:{},data:t}):n),f(a)}function l(e){var t,i="";return i+="\n "+f((t=e&&e.options,t=null==t||t===!1?t:t.anchorTitle,typeof t===h?t.apply(e):t))+"\n "}function c(e,t){var a,n,r="";return r+="\n ",(n=i.data)?a=n.call(e,{hash:{},data:t}):(n=e&&e.data,a=typeof n===h?n.call(e,{hash:{},data:t}):n),r+=f(a)+"\n "}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u="",h="function",f=this.escapeExpression,m=this;return u+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"].control=function(e,t,i,a,n){function r(e,t){var a,n,r="";return r+='\n \n "}function o(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.labelClass,typeof t===f?t.apply(e):t))}function s(){var e="";return e}function l(e,t){var a,n="";return n+='\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function c(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='\n"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-display"]=this.HandlebarsPrecompiled["web-display"]||{},this.HandlebarsPrecompiled["web-display"].form=function(e,t,i,a,n){function r(){var e="";return e}function o(e,t,a){var n,r="";return r+="\n ",n=i.each.call(e,(n=e&&e.options,null==n||n===!1?n:n.buttons),{hash:{},inverse:v.noop,fn:v.programWithDepth(4,s,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n "}function s(e,t,a){var n,r,o,s="";return s+='\n \n "}function l(){return'type="submit"'}function c(){return'type="reset"'}function d(e,t){var a,n,r="";return r+=g((a=null==t||t===!1?t:t.key,typeof a===m?a.apply(e):a))+'="',(n=i.value)?a=n.call(e,{hash:{},data:t}):(n=e&&e.value,a=typeof n===m?n.call(e,{hash:{},data:t}):n),r+=g(a)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var p,u,h,f="",m="function",g=this.escapeExpression,v=this,y=i.helperMissing,b=i.blockHelperMissing;return f+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["container-array-actionbar"]=function(e,t,i,a,n){function r(e,t,a){var n,r,l="";return l+='\n \n "}function o(e){var t,i="";return i+='\n \n '}function s(e,t){var a,n;return(n=i.label)?a=n.call(e,{hash:{},data:t}):(n=e&&e.label,a=typeof n===p?n.call(e,{hash:{},data:t}):n),a||0===a?a:""}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var l,c,d="",p="function",u=this.escapeExpression,h=this;return d+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["container-array-item"]=function(e,t,i,a,n){function r(e,t){var a,n,r,s="";return s+='\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n "}function l(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}function c(){var e="";return e}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["control-any"]=function(e,t,i,a,n){function r(){return'readonly="readonly"'}function o(e,t){var a,n,r="";return r+='name="',(n=i.name)?a=n.call(e,{hash:{},data:t}):(n=e&&e.name,a=typeof n===p?n.call(e,{hash:{},data:t}):n),r+=u(a)+'"'}function s(e,t){var i,a="";return a+="data-"+u((i=null==t||t===!1?t:t.key,typeof i===p?i.apply(e):i))+'="'+u(typeof e===p?e.apply(e):e)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var l,c,d="",p="function",u=this.escapeExpression,h=this;return d+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"]["control-checkbox"]=function(e,t,i,a,n){function r(e,t,a){var n,r="";return r+="\n\n ",n=i.each.call(e,e&&e.checkboxOptions,{hash:{},inverse:m.noop,fn:m.programWithDepth(2,o,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n\n "}function o(e,t,a){var n,r,o="";return o+='\n\n\n \n ',a=e&&e.options,a=null==a||a===!1?a:a.helper,a=typeof a===f?a.apply(e):a,(a||0===a)&&(n+=a),n+="\n
\n " -}function c(e){var t;return m((t=e&&e.options,t=null==t||t===!1?t:t.helperClass,typeof t===f?t.apply(e):t))}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var d,p,u,h="",f="function",m=this.escapeExpression,g=this,v=i.blockHelperMissing;return h+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].form=function(e,t,i,a,n){function r(){var e="";return e}function o(e,t,a){var n,r="";return r+="\n ",n=i.each.call(e,(n=e&&e.options,null==n||n===!1?n:n.buttons),{hash:{},inverse:m.noop,fn:m.programWithDepth(4,s,t,a),data:t}),(n||0===n)&&(r+=n),r+="\n "}function s(e,t,a){var n,r,o="";return o+='\n \n "}function l(e,t){var a,n,r="";return r+=f((a=null==t||t===!1?t:t.key,typeof a===h?a.apply(e):a))+'="',(n=i.value)?a=n.call(e,{hash:{},data:t}):(n=e&&e.value,a=typeof n===h?n.call(e,{hash:{},data:t}):n),r+=f(a)+'"'}this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var c,d,p,u="",h="function",f=this.escapeExpression,m=this,g=i.blockHelperMissing;return u+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].message=function(e,t,i,a,n){this.compilerInfo=[4,">= 1.0.0"],i=this.merge(i,e.helpers),n=n||{};var r,o,s="",l="function";return s+='"},this.HandlebarsPrecompiled=this.HandlebarsPrecompiled||{},this.HandlebarsPrecompiled["web-edit"]=this.HandlebarsPrecompiled["web-edit"]||{},this.HandlebarsPrecompiled["web-edit"].wizard=function(e,t,i,a,n){function r(e,t){var a,n="";return n+='\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-image"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-radio"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-select"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper, options; - buffer += "\n "; - stack1 = (helper = helpers.compare || (depth0 && depth0.compare),options={hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data},helper ? helper.call(depth0, (depth0 && depth0.value), (depth1 && depth1.data), options) : helperMissing.call(depth0, "compare", (depth0 && depth0.value), (depth1 && depth1.data), options)); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.text) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.text); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-text"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-textarea"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control-url"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "target=\"" - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTarget)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\""; - return buffer; - } - -function program3(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program5(depth0,data) { - - var stack1, helper; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - return escapeExpression(stack1); - } - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n " - + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.anchorTitle)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "\n "; - return buffer; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n "; - if (helper = helpers.data) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.data); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\n "; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["control"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.labelClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program4(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program6(depth0,data) { - - var buffer = "", stack1; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += "\n"; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-display"] = this["HandlebarsPrecompiled"]["web-display"] || {}; -this["HandlebarsPrecompiled"]["web-display"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper, options; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - - return "type=\"submit\""; - } - -function program7(depth0,data) { - - - return "type=\"reset\""; - } - -function program9(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-actionbar"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n \n "; - return buffer; - } - -function program4(depth0,data) { - - var stack1, helper; - if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - if(stack1 || stack1 === 0) { return stack1; } - else { return ''; } - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["container-array-item"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1, helper, options; - buffer += "\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program5(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - -function program7(depth0,data) { - - var buffer = ""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-any"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data) { - - - return "readonly=\"readonly\""; - } - -function program3(depth0,data) { - - var buffer = "", stack1, helper; - buffer += "name=\""; - if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "data-" - + escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\"" - + escapeExpression((typeof depth0 === functionType ? depth0.apply(depth0) : depth0)) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["control-checkbox"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this; - -function program1(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n\n "; - stack1 = helpers.each.call(depth0, (depth0 && depth0.checkboxOptions), {hash:{},inverse:self.noop,fn:self.programWithDepth(2, program2, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n "; - return buffer; - } -function program2(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n\n\n \n "; - stack1 = ((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helper)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n
\n "; - return buffer; - } -function program7(depth0,data) { - - var stack1; - return escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.helperClass)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)); - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["form"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing; - -function program1(depth0,data) { - - var buffer = ""; - return buffer; - } - -function program3(depth0,data,depth1) { - - var buffer = "", stack1; - buffer += "\n "; - stack1 = helpers.each.call(depth0, ((stack1 = (depth0 && depth0.options)),stack1 == null || stack1 === false ? stack1 : stack1.buttons), {hash:{},inverse:self.noop,fn:self.programWithDepth(4, program4, data, depth1),data:data}); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer; - } -function program4(depth0,data,depth2) { - - var buffer = "", stack1, helper; - buffer += "\n \n "; - return buffer; - } -function program5(depth0,data) { - - var buffer = "", stack1, helper; - buffer += escapeExpression(((stack1 = (data == null || data === false ? data : data.key)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1)) - + "=\""; - if (helper = helpers.value) { stack1 = helper.call(depth0, {hash:{},data:data}); } - else { helper = (depth0 && depth0.value); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } - buffer += escapeExpression(stack1) - + "\""; - return buffer; - } - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["message"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, helper, functionType="function"; - - - buffer += ""; - return buffer; - }; -this["HandlebarsPrecompiled"] = this["HandlebarsPrecompiled"] || {}; -this["HandlebarsPrecompiled"]["web-edit"] = this["HandlebarsPrecompiled"]["web-edit"] || {}; -this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = function (Handlebars,depth0,helpers,partials,data) { - this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; - var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n
- *
- * Alpaca(el, config);
- *
- *
- *
- * The full syntax is:
- *
- *
- *
- * Alpaca(el, {
- * "data" : {Any} field data (optional),
- * "schema": {Object} field schema (optional),
- * "options" : {Object} field options (optional),
- * "view": {Object|String} field view (object or id reference) (optional),
- * "render": {Function} callback function for replacing default rendering method (optional),
- * "postRender": {Function} callback function for post-rendering (optional),
- * "error": {Function} callback function for error handling (optional),
- * "connector": {Alpaca.Connector} connector for retrieving or storing data, schema, options, view and templates. (optional)
- * });
- *
- *
- *
- * @returns {*}
- */
- var Alpaca = function()
- {
- var args = Alpaca.makeArray(arguments);
- if (args.length === 0) {
- // illegal
- return Alpaca.throwDefaultError("You must supply at least one argument. This argument can either be a DOM element against which Alpaca will generate a form or it can be a function name. See http://www.alpacajs.org for more details.");
- }
-
- // element is the first argument (either a string or a DOM element)
- var el = args[0];
- if (el && Alpaca.isString(el)) {
- el = $("#" + el);
- }
-
- // other arguments we may want to figure out
- var data = null;
- var schema = null;
- var options = null;
- var view = null;
- var callback = null;
- var renderedCallback = null;
- var errorCallback = null;
- var connector = null;
- var notTopLevel = false;
- var initialSettings = {};
-
- // if these options are provided, then data, schema, options and source are loaded via connector
- var dataSource = null;
- var schemaSource = null;
- var optionsSource = null;
- var viewSource = null;
-
- // hands back the field instance that is bound directly under the element el
- var findExistingAlpacaBinding = function()
- {
- var existing = null;
-
- var topElements = $(el).find(":first");
- if (topElements.length > 0)
- {
- // does a field binding exist?
- var fieldId = $(topElements[0]).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var _existing = Alpaca.fieldInstances[fieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- else
- {
- // does a form binding exist?
- var formId = $(topElements[0]).attr("data-alpaca-form-id");
- if (formId)
- {
- var subElements = $(topElements[0]).find(":first");
- if (subElements.length > 0)
- {
- var subFieldId = $(subElements[0]).attr("data-alpaca-field-id");
- if (subFieldId)
- {
- var _existing = Alpaca.fieldInstances[subFieldId];
- if (_existing) {
- existing = _existing;
- }
- }
- }
- }
- }
- }
-
- return existing;
- };
-
- var specialFunctionNames = ["get", "exists", "destroy"];
- var isSpecialFunction = (args.length > 1 && Alpaca.isString(args[1]) && (specialFunctionNames.indexOf(args[1]) > -1));
-
- var existing = findExistingAlpacaBinding();
- if (existing || isSpecialFunction)
- {
- if (isSpecialFunction)
- {
- // second argument must be a special function name
- var specialFunctionName = args[1];
- if ("get" === specialFunctionName) {
- return existing;
- }
- else if ("exists" === specialFunctionName) {
- return (existing ? true : false);
- }
- else if ("destroy" === specialFunctionName) {
- existing.destroy();
- return;
- }
-
- return Alpaca.throwDefaultError("Unknown special function: " + specialFunctionName);
- }
-
- return existing;
- }
- else
- {
- var config = null;
-
- // just a dom element, no other args?
- if (args.length === 1)
- {
- // grab the data inside of the element and use that for config
- var jsonString = $(el).text();
-
- config = JSON.parse(jsonString);
- $(el).html("");
- }
- else
- {
- if (Alpaca.isObject(args[1]))
- {
- config = args[1];
- }
- else if (Alpaca.isFunction(args[1]))
- {
- config = args[1]();
- }
- else
- {
- config = {
- "data": args[1]
- };
- }
- }
-
- if (!config)
- {
- return Alpaca.throwDefaultError("Unable to determine Alpaca configuration");
- }
-
- data = config.data;
- schema = config.schema;
- options = config.options;
- view = config.view;
- callback = config.render;
- if (config.callback) {
- callback = config.callback;
- }
- renderedCallback = config.postRender;
- errorCallback = config.error;
- connector = config.connector;
-
- // sources
- dataSource = config.dataSource;
- schemaSource = config.schemaSource;
- optionsSource = config.optionsSource;
- viewSource = config.viewSource;
-
- // other
- if (config.ui) {
- initialSettings["ui"] = config.ui;
- }
- if (config.type) {
- initialSettings["type"] = config.type;
- }
- if (!Alpaca.isEmpty(config.notTopLevel)) {
- notTopLevel = config.notTopLevel;
- }
- }
-
- // if no error callback is provided, we fall back to a browser alert
- if (Alpaca.isEmpty(errorCallback)) {
- errorCallback = Alpaca.defaultErrorCallback;
- }
-
- if (Alpaca.isEmpty(connector)) {
- var ConnectorClass = Alpaca.getConnectorClass("default");
- connector = new ConnectorClass("default");
- }
-
- // For second or deeper level of fields, default loader should be the one to do loadAll
- // since schema, data, options and view should have already been loaded.
- // Unless we want to load individual fields (other than the templates) using the provided
- // loader, this should be good enough. The benefit is saving time on loader format checking.
-
- var loadAllConnector = connector;
-
- if (notTopLevel) {
- var LoadAllConnectorClass = Alpaca.getConnectorClass("default");
- loadAllConnector = new LoadAllConnectorClass("default");
- }
-
- if (!options) {
- options = {};
- }
-
- // resets the hideInitValidationError back to default state after first render
- var _resetInitValidationError = function(field)
- {
- // if this is the top-level alpaca field, then we call for validation state to be recalculated across
- // all child fields
- if (!field.parent)
- {
- // final call to update validation state
- // only do this if we're not supposed to suspend initial validation errors
- if (!field.hideInitValidationError)
- {
- field.refreshValidationState(true);
- }
-
- // force hideInitValidationError to false for field and all children
- if (field.view.type !== 'view')
- {
- Alpaca.fieldApplyFieldAndChildren(field, function(field) {
-
- // set to false after first validation (even if in CREATE mode, we only force init validation error false on first render)
- field.hideInitValidationError = false;
-
- });
- }
- }
- };
-
- // wrap rendered callback to allow for UI treatment (dom focus, etc)
- var _renderedCallback = function(field)
- {
- // if top level, apply a unique observable scope id
- if (!field.parent)
- {
- field.observableScope = Alpaca.generateId();
- }
-
- // if top level and focus has not been specified, then auto-set
- if (Alpaca.isUndefined(options.focus) && !field.parent) {
- options.focus = Alpaca.defaultFocus;
- }
-
- // auto-set the focus?
- if (options && options.focus)
- {
- window.setTimeout(function() {
-
- var doFocus = function(__field)
- {
- __field.suspendBlurFocus = true;
- __field.focus();
- __field.suspendBlurFocus = false;
- };
-
- if (options.focus)
- {
- if (field.isControlField && field.isAutoFocusable())
- {
- // just focus on this one
- doFocus(field);
- }
- else if (field.isContainerField)
- {
- // if focus = true, then focus on the first child control if it is auto-focusable
- // and not read-only
- if (options.focus === true)
- {
- // pick first element in form
- if (field.children && field.children.length > 0)
- {
- for (var z = 0; z < field.children.length; z++)
- {
- if (field.children[z].isControlField)
- {
- if (field.children[z].isAutoFocusable() && !field.children[z].options.readonly)
- {
- doFocus(field.children[z]);
- break;
- }
- }
- }
- }
- }
- else if (typeof(options.focus) === "string")
- {
- // assume it is a path to the child
- var child = field.getControlByPath(options.focus);
- if (child && child.isControlField && child.isAutoFocusable())
- {
- doFocus(child);
- }
- }
- }
-
- _resetInitValidationError(field);
- }
- }, 500);
- }
- else
- {
- _resetInitValidationError(field);
- }
-
- if (renderedCallback)
- {
- renderedCallback(field);
- }
- };
-
- loadAllConnector.loadAll({
- "data": data,
- "schema": schema,
- "options": options,
- "view": view,
- "dataSource": dataSource,
- "schemaSource": schemaSource,
- "optionsSource": optionsSource,
- "viewSource": viewSource
- }, function(loadedData, loadedOptions, loadedSchema, loadedView) {
-
- // for cases where things could not be loaded via source loaders, fall back to what may have been passed
- // in directly as values
-
- loadedData = loadedData ? loadedData : data;
- loadedSchema = loadedSchema ? loadedSchema: schema;
- loadedOptions = loadedOptions ? loadedOptions : options;
- loadedView = loadedView ? loadedView : view;
-
- // some defaults for the case where data is null
- // if schema + options are not provided, we assume a text field
-
- if (Alpaca.isEmpty(loadedData))
- {
- if (Alpaca.isEmpty(loadedSchema) && (Alpaca.isEmpty(loadedOptions) || Alpaca.isEmpty(loadedOptions.type)))
- {
- loadedData = "";
-
- if (Alpaca.isEmpty(loadedOptions))
- {
- loadedOptions = "text";
- }
- else if (options && Alpaca.isObject(options))
- {
- loadedOptions.type = "text";
- }
- }
- }
-
- if (loadedOptions.view)
- {
- loadedView = loadedOptions.view;
- }
-
- // init alpaca
- return Alpaca.init(el, loadedData, loadedOptions, loadedSchema, loadedView, initialSettings, callback, _renderedCallback, connector, errorCallback);
-
- }, function (loadError) {
- errorCallback(loadError);
- return null;
- });
- };
-
- /**
- * @namespace Namespace for all Alpaca Field Class Implementations.
- */
- Alpaca.Fields = { };
-
- /**
- * @namespace Namespace for all Alpaca Connector Class Implementations.
- */
- Alpaca.Connectors = { };
-
- Alpaca.Extend = $.extend;
-
- Alpaca.Create = function()
- {
- var args = Array.prototype.slice.call(arguments);
- args.unshift({});
-
- return $.extend.apply(this, args);
- };
-
- // static methods and properties
- Alpaca.Extend(Alpaca,
- /** @lends Alpaca */
- {
- /**
- * Makes an array.
- *
- * @param {Any} nonArray A non-array variable.
- * @returns {Array} Array out of the non-array variable.
- */
- makeArray : function(nonArray) {
- return Array.prototype.slice.call(nonArray);
- },
-
- /**
- * Finds whether the type of a variable is function.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a function, false otherwise.
- */
- isFunction: function(obj) {
- return Object.prototype.toString.call(obj) === "[object Function]";
- },
-
- /**
- * Finds whether the type of a variable is string.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a string, false otherwise.
- */
- isString: function(obj) {
- return (typeof obj === "string");
- },
-
- /**
- * Finds whether the type of a variable is object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an object, false otherwise.
- */
- isObject: function(obj) {
- return !Alpaca.isUndefined(obj) && Object.prototype.toString.call(obj) === '[object Object]';
- },
-
- /**
- * Finds whether the type of a variable is a plain, non-prototyped object.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a plain object, false otherwise.
- */
- isPlainObject: function(obj) {
- return $.isPlainObject(obj);
- },
-
- /**
- * Finds whether the type of a variable is number.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a number, false otherwise.
- */
- isNumber: function(obj) {
- return (typeof obj === "number");
- },
-
- /**
- * Finds whether the type of a variable is array.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is an array, false otherwise.
- */
- isArray: function(obj) {
- return obj instanceof Array;
- },
-
- /**
- * Finds whether the type of a variable is boolean.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a boolean, false otherwise.
- */
- isBoolean: function(obj) {
- return (typeof obj === "boolean");
- },
-
- /**
- * Finds whether the type of a variable is undefined.
- * @param {Any} obj The variable being evaluated.
- * @returns {Boolean} True if the variable is a undefined, false otherwise.
- */
- isUndefined: function(obj) {
- return (typeof obj == "undefined");
- },
-
- /**
- * Strips any excess whitespace characters from the given text.
- * Returns the trimmed string.
- *
- * @param str
- *
- * @return trimmed string
- */
- trim: function(text)
- {
- var trimmed = text;
-
- if (trimmed && Alpaca.isString(trimmed))
- {
- trimmed = trimmed.replace(/^\s+|\s+$/g, '');
- }
-
- return trimmed;
- },
-
- /**
- * Provides a safe conversion of an HTML textual string into a DOM object.
- *
- * @param x
- * @return {*}
- */
- safeDomParse: function(x)
- {
- if (x && Alpaca.isString(x))
- {
- x = Alpaca.trim(x);
-
- // convert to dom
- var converted = null;
- try
- {
- converted = $(x);
- }
- catch (e)
- {
- // make another attempt to account for safety in some browsers
- x = "displayReadonly
attribute set to false, the read-only field will not appear.",
- "type": "boolean",
- "default": false
- },
- "required": {
- "title": "Required",
- "description": "Indicates whether the field's value is required. If set to true, the field must take on a valid value and cannnot be left empty or unassigned.",
- "type": "boolean",
- "default": false
- },
- "default": {
- "title": "Default",
- "description": "The default value to be assigned for this property. If the data for the field is empty or not provided, this default value will be plugged in for you. Specify a default value when you want to pre-populate the field's value ahead of time.",
- "type": "any"
- },
- "type": {
- "title": "Type",
- "description": "Data type of the property.",
- "type": "string",
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Data format of the property.",
- "type": "string"
- },
- "disallow": {
- "title": "Disallowed Values",
- "description": "List of disallowed values for the property.",
- "type": "array"
- },
- "dependencies": {
- "title": "Dependencies",
- "description": "List of property dependencies.",
- "type": "array"
- }
- }
- };
- if (this.getType && !Alpaca.isValEmpty(this.getType())) {
- schemaOfSchema.properties.type['default'] = this.getType();
- schemaOfSchema.properties.type['enum'] = [this.getType()];
- }
- return schemaOfSchema;
- },
-
- /**
- * Returns Alpaca options for the schema properties that managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the schema properties that are managed by this class.
- */
- getOptionsForSchema: function() {
- return {
- "fields": {
- "title": {
- "helper": "Field short description",
- "type": "text"
- },
- "description": {
- "helper": "Field detailed description",
- "type": "textarea"
- },
- "readonly": {
- "helper": "Field will be read only if checked",
- "rightLabel": "This field is read-only",
- "type": "checkbox"
- },
- "required": {
- "helper": "Field value must be set if checked",
- "rightLabel": "This field is required",
- "type": "checkbox"
- },
- "default": {
- "helper": "Field default value",
- "type": "textarea"
- },
- "type": {
- "helper": "Field data type",
- "type": "text"
- },
- "format": {
- "type": "select",
- "dataSource": function(callback) {
- for (var key in Alpaca.defaultFormatFieldMapping)
- {
- this.selectOptions.push({
- "value": key,
- "text": key
- });
- }
-
- callback();
- }
- },
- "disallow": {
- "helper": "Disallowed values for the field",
- "itemLabel":"Value",
- "type": "array"
- },
- "dependencies": {
- "helper": "Field Dependencies",
- "multiple":true,
- "size":3,
- "type": "select",
- "dataSource": function (field, callback) {
- if (field.parent && field.parent.schemaParent && field.parent.schemaParent.parent) {
- for (var key in field.parent.schemaParent.parent.childrenByPropertyId) {
- if (key != field.parent.schemaParent.propertyId) { // jshint ignore:line
- field.selectOptions.push({
- "value": key,
- "text": key
- });
- }
- }
- }
- if (callback) {
- callback();
- }
- }
- }
- }
- };
- },
-
- /**
- * Returns JSON schema of the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} JSON schema of the Alpaca options that are managed by this class.
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = {
- "title": "Options for " + this.getTitle(),
- "description": this.getDescription() + " (Options)",
- "type": "object",
- "properties": {
- "form":{},
- "id": {
- "title": "Field Id",
- "description": "Unique field id. Auto-generated if not provided.",
- "type": "string"
- },
- "type": {
- "title": "Field Type",
- "description": "Field type.",
- "type": "string",
- "default": this.getFieldType(),
- "readonly": true
- },
- "validate": {
- "title": "Validation",
- "description": "Field validation is required if true.",
- "type": "boolean",
- "default": true
- },
- "showMessages": {
- "title": "Show Messages",
- "description": "Display validation messages if true.",
- "type": "boolean",
- "default": true
- },
- "disabled": {
- "title": "Disabled",
- "description": "Field will be disabled if true.",
- "type": "boolean",
- "default": false
- },
- "readonly": {
- "title": "Readonly",
- "description": "Field will be readonly if true.",
- "type": "boolean",
- "default": false
- },
- "hidden": {
- "title": "Hidden",
- "description": "Field will be hidden if true.",
- "type": "boolean",
- "default": false
- },
- "label": {
- "title": "Label",
- "description": "Field label.",
- "type": "string"
- },
- "helper": {
- "title": "Helper",
- "description": "Field help message.",
- "type": "string"
- },
- "fieldClass": {
- "title": "CSS class",
- "description": "Specifies one or more CSS classes that should be applied to the dom element for this field once it is rendered. Supports a single value, comma-delimited values, space-delimited values or values passed in as an array.",
- "type": "string"
- },
- "hideInitValidationError" : {
- "title": "Hide Initial Validation Errors",
- "description" : "Hide initial validation errors if true.",
- "type": "boolean",
- "default": false
- },
- "focus": {
- "title": "Focus",
- "description": "If true, the initial focus for the form will be set to the first child element (usually the first field in the form). If a field name or path is provided, then the specified child field will receive focus. For example, you might set focus to 'name' (selecting the 'name' field) or you might set it to 'client/name' which picks the 'name' field on the 'client' object.",
- "type": "checkbox",
- "default": true
- },
- "optionLabels": {
- "title": "Enumerated Value Labels",
- "description": "An array of string labels for items in the enum array",
- "type": "array"
- },
- "view": {
- "title": "Override of the view for this field",
- "description": "Allows for this field to be rendered with a different view (such as 'display' or 'create')",
- "type": "string"
- }
- }
- };
- if (this.isTopLevel()) {
-
- schemaOfOptions.properties.form = {
- "title": "Form",
- "description": "Options for rendering the FORM tag.",
- "type": "object",
- "properties": {
- "attributes": {
- "title": "Form Attributes",
- "description": "List of attributes for the FORM tag.",
- "type": "object",
- "properties": {
- "id": {
- "title": "Id",
- "description": "Unique form id. Auto-generated if not provided.",
- "type": "string"
- },
- "action": {
- "title": "Action",
- "description": "Form submission endpoint",
- "type": "string"
- },
- "method": {
- "title": "Method",
- "description": "Form submission method",
- "enum":["post","get"],
- "type": "string"
- },
- "rubyrails": {
- "title": "Ruby On Rails",
- "description": "Ruby on Rails Name Standard",
- "enum": ["true", "false"],
- "type": "string"
- },
- "name": {
- "title": "Name",
- "description": "Form name",
- "type": "string"
- },
- "focus": {
- "title": "Focus",
- "description": "Focus Setting",
- "type": "any"
- }
- }
- },
- "buttons": {
- "title": "Form Buttons",
- "description": "Configuration for form-bound buttons",
- "type": "object",
- "properties": {
- "submit": {
- "type": "object",
- "title": "Submit Button",
- "required": false
- },
- "reset": {
- "type": "object",
- "title": "Reset button",
- "required": false
- }
- }
- },
- "toggleSubmitValidState": {
- "title": "Toggle Submit Valid State",
- "description": "Toggle the validity state of the Submit button",
- "type": "boolean",
- "default": true
- }
- }
- };
-
- } else {
- delete schemaOfOptions.properties.form;
- }
-
- return schemaOfOptions;
- },
-
- /**
- * Returns Alpaca options for the Alpaca options that are managed by this class.
- *
- * @private
- * @returns {Object} Alpaca options for the Alpaca options that are managed by this class.
- */
- getOptionsForOptions: function() {
- var optionsForOptions = {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "type": {
- "type": "text"
- },
- "validate": {
- "rightLabel": "Enforce validation",
- "type": "checkbox"
- },
- "showMessages": {
- "rightLabel":"Show validation messages",
- "type": "checkbox"
- },
- "disabled": {
- "rightLabel":"Disable this field",
- "type": "checkbox"
- },
- "hidden": {
- "type": "checkbox",
- "rightLabel": "Hide this field"
- },
- "label": {
- "type": "text"
- },
- "helper": {
- "type": "textarea"
- },
- "fieldClass": {
- "type": "text"
- },
- "hideInitValidationError": {
- "rightLabel": "Hide initial validation errors",
- "type": "checkbox"
- },
- "focus": {
- "type": "checkbox",
- "rightLabel": "Auto-focus first child field"
- },
- "optionLabels": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "view": {
- "type": "text"
- }
- }
- };
- if (this.isTopLevel()) {
- optionsForOptions.fields.form = {
- "type": "object",
- "fields": {
- "attributes": {
- "type": "object",
- "fields": {
- "id": {
- "type": "text",
- "readonly": true
- },
- "action": {
- "type": "text"
- },
- "method": {
- "type": "select"
- },
- "name": {
- "type": "text"
- }
- }
- }
- }
- };
- }
-
- return optionsForOptions;
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "disallowValue": "{0} are disallowed values.",
- "notOptional": "This field is not optional."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ControlField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ControlField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a control field.
- */
- onConstruct: function()
- {
- var _this = this;
-
- this.isControlField = true;
-
- // helper method for getting val() from the control
- // handles conversion to the correct scalar type
- this._getControlVal = function(ensureProperType) {
- var val = null;
-
- if (this.control)
- {
- val = $(this.control).val();
-
- if (ensureProperType)
- {
- val = _this.ensureProperType(val);
- }
- }
-
- return val;
- };
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var controlTemplateType = self.resolveControlTemplateType();
- if (!controlTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for control: " + self.getFieldType());
- }
-
- this.controlDescriptor = this.view.getTemplateDescriptor("control-" + controlTemplateType, self);
- },
-
- getControlEl: function()
- {
- return this.control;
- },
-
- resolveControlTemplateType: function()
- {
- var self = this;
-
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("control-" + b.getFieldType(), self);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- onSetup: function()
- {
-
- },
-
- isAutoFocusable: function()
- {
- return true;
- },
-
- /**
- * For control fields, we use the "control" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "control";
- },
-
- /**
- * Add a "control" dom element inside of the field which houses our custom control.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.control = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTROL_FIELD);
- this.control.removeClass(Alpaca.MARKER_CLASS_CONTROL_FIELD);
-
- // render
- self.prepareControlModel(function(model) {
- self.beforeRenderControl(model, function() {
- self.renderControl(model, function(controlField) {
-
- if (controlField)
- {
- self.control.replaceWith(controlField);
- self.control = controlField;
-
- self.control.addClass(Alpaca.CLASS_CONTROL);
- }
-
- // CALLBACK: "control"
- self.fireCallback("control");
-
- self.afterRenderControl(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the control.
- *
- * @param callback function(model)
- */
- prepareControlModel: function(callback)
- {
- var self = this;
-
- var model = {};
- model.id = this.getId();
- model.name = this.name;
- model.options = this.options;
- model.schema = this.schema;
- model.data = this.data;
- model.required = this.isRequired();
- model.view = this.view;
-
- callback(model);
- },
-
- /**
- * Called before the control is rendered.
- *
- * @extension-point
- *
- * @param callback
- */
- beforeRenderControl: function(model, callback)
- {
- callback();
- },
-
- /**
- * Called after the control is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- if (!self.firstUpdateObservableFire)
- {
- if ((typeof(self.data) == "undefined") || self.data == null)
- {
- // do not handle
- }
- else
- {
- self.firstUpdateObservableFire = true;
- self.updateObservable();
- }
- }
-
- callback();
- },
-
- /**
- * Renders the control into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderControl: function(model, callback)
- {
- var control = null;
-
- if (this.controlDescriptor)
- {
- control = Alpaca.tmpl(this.controlDescriptor, model);
- }
-
- callback(control);
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- /*
- // store reference to the label
- this.labelDiv = $(this.field).find(".alpaca-controlfield-label");
- var labelDiv = $('.alpaca-controlfield-label', this.outerEl);
- if (labelDiv.length) {
- this.labelDiv = labelDiv;
- }
-
- var helperDiv = $('.alpaca-controlfield-helper', this.outerEl);
- if (helperDiv.length) {
- this.helperDiv = helperDiv;
- }
- */
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#setDefault
- */
- setDefault: function() {
- var defaultData = Alpaca.isEmpty(this.schema['default']) ? "" : this.schema['default'];
- this.setValue(defaultData);
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- if (this.schema["enum"]) {
- var val = this.data;
- val = this.getValue();
- /*this.getValue();*/
- if (!this.isRequired() && Alpaca.isValEmpty(val)) {
- return true;
- }
- if ($.inArray(val, this.schema["enum"]) > -1) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateEnum();
- valInfo["invalidValueOfEnum"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidValueOfEnum"), [this.schema["enum"].join(', '), this.data]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidValueOfEnum"]["status"];
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- this.initControlEvents();
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- var control = this.control;
-
- control.click(function(e) {
- self.onClick.call(self, e);
- self.trigger("click", e);
- });
-
- // trigger control level handlers for things that happen to input element
- control.change(function(e) {
-
- // we use a timeout here because we want this to run AFTER control click handlers
- setTimeout(function() {
- self.onChange.call(self, e);
- self.triggerWithPropagation("change", e);
- }, 250);
- });
-
- control.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- control.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
-
- control.keypress(function(e) {
- self.onKeyPress.call(self, e);
- self.trigger("keypress", e);
- });
-
- control.keyup(function(e) {
- self.onKeyUp.call(self, e);
- self.trigger("keyup", e);
- });
-
- control.keydown(function(e) {
- self.onKeyDown.call(self, e);
- self.trigger("keydown", e);
- });
- },
-
- /**
- * Callback for when a key press event is received for the field control.
- *
- * @param {Object} e keypress event
- */
- onKeyPress: function(e)
- {
- var self = this;
-
- // if the field is currently invalid, then we provide early feedback to the user as to when they enter
- // if the field was valid, we don't render invalidation feedback until they blur the field
-
- // was the control valid previously?
- var wasValid = this.isValid();
- if (!wasValid)
- {
- //
- // we use a timeout because at this exact moment, the value of the control is still the old value
- // jQuery raises the keypress event ahead of the input receiving the new data which would incorporate
- // the key that was pressed
- //
- // this timeout provides the browser with enough time to plug the value into the input control
- // which the validation logic uses to determine whether the control is now in a valid state
- //
- window.setTimeout(function() {
- self.refreshValidationState();
- }, 50);
- }
-
- },
-
- /**
- * Callback for when a key down event is received for the field control.
- *
- * @param {Object} e keydown event
- */
- onKeyDown: function(e)
- {
- },
-
- /**
- * Callback for when a key up event is received for the field control.
- *
- * @param {Object} e keyup event
- */
- onKeyUp: function(e)
- {
- },
-
- /**
- * Handler for click event.
- *
- * @param {Object} e Click event.
- */
- onClick: function(e)
- {
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", true);
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- if (this.control && this.control.length > 0)
- {
- $(this.control).prop("disabled", false);
- }
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumerated Values",
- "description": "List of specific values for this property",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "enum": {
- "itemLabel":"Value",
- "type": "array"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "name": {
- "title": "Field Name",
- "description": "Field Name.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "name": {
- "type": "text"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
- // Registers additional messages
- Alpaca.registerMessages({
- "invalidValueOfEnum": "This field should have one of the values in {0}. Current value is: {1}"
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.ContainerField = Alpaca.Field.extend(
- /**
- * @lends Alpaca.ContainerField.prototype
- */
- {
- /**
- * Called during construction to signal that this field is a container field.
- */
- onConstruct: function()
- {
- this.isContainerField = true;
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return true;
- },
-
- getContainerEl: function()
- {
- return this.container;
- },
-
- /**
- * For container fields, we use the "container" template as the primary.
- *
- * @see Alpaca.Field#getTemplateDescriptorId
- * @returns {string}
- */
- getTemplateDescriptorId : function ()
- {
- return "container";
- },
-
- resolveContainerTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType(), this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- resolveContainerItemTemplateType: function()
- {
- // we assume the field type and then check the view to see if there is a template for this view
- // if not, we walk the parent chain until we find a template type
-
- var finished = false;
- var selectedType = null;
-
- var b = this;
- do
- {
- if (!b.getFieldType)
- {
- finished = true;
- }
- else
- {
- var d = this.view.getTemplateDescriptor("container-" + b.getFieldType() + "-item", this);
- if (d)
- {
- selectedType = b.getFieldType();
- finished = true;
- }
- else
- {
- b = b.constructor.ancestor.prototype;
- }
- }
- }
- while (!finished);
-
- return selectedType;
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerTemplateType = self.resolveContainerTemplateType();
- if (!containerTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container: " + self.getFieldType());
- }
-
- this.containerDescriptor = this.view.getTemplateDescriptor("container-" + containerTemplateType, self);
-
- var collapsible = true;
-
- if (!Alpaca.isEmpty(this.view.collapsible)) {
- collapsible = this.view.collapsible;
- }
-
- if (!Alpaca.isEmpty(this.options.collapsible)) {
- collapsible = this.options.collapsible;
- }
-
- this.options.collapsible = collapsible;
-
- var legendStyle = "button";
-
- if (!Alpaca.isEmpty(this.view.legendStyle)) {
- legendStyle = this.view.legendStyle;
- }
-
- if (!Alpaca.isEmpty(this.options.legendStyle)) {
- legendStyle = this.options.legendStyle;
- }
-
- this.options.legendStyle = legendStyle;
-
- //Lazy loading
- this.lazyLoading = false;
- if (!Alpaca.isEmpty(this.options.lazyLoading)) {
- this.lazyLoading = this.options.lazyLoading;
- if (this.lazyLoading) {
- this.options.collapsed = true;
- }
- //delete this.options.lazyLoading;
- }
- // holders of references to children
- this.children = [];
- this.childrenById = {};
- this.childrenByPropertyId = {};
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // if this container is DOM-wrapped with a form, then release the form
- if (this.form)
- {
- this.form.destroy(true); // pass in true so that we don't call back recursively
- delete this.form;
- }
-
- // destroy any child controls
- Alpaca.each(this.children, function() {
- this.destroy();
- });
-
- // call up to base method
- this.base();
- },
-
- /**
- * Add a "container" dom element inside of the field which houses our custom container.
- *
- * @see Alpaca.Field#renderField
- */
- renderFieldElements: function(callback) {
-
- var self = this;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.container = $(this.field).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD);
- this.container.removeClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD);
-
- // render
- self.prepareContainerModel(function(model) {
- self.beforeRenderContainer(model, function() {
- self.renderContainer(model, function(containerField) {
-
- if (containerField)
- {
- self.container.replaceWith(containerField);
- self.container = containerField;
-
- self.container.addClass(Alpaca.CLASS_CONTAINER);
- }
-
- // mark the form field with "alpaca-horizontal" or "alpaca-vertical"
- if (self.view.horizontal)
- {
- self.container.addClass("alpaca-horizontal");
- }
- else
- {
- self.container.addClass("alpaca-vertical");
- }
-
- // CALLBACK: "container"
- self.fireCallback("container");
-
- self.afterRenderContainer(model, function() {
-
- callback();
- });
-
- });
- });
- });
- },
-
- /**
- * Prepares the model for use in rendering the container.
- *
- * @param callback function(model)
- */
- prepareContainerModel: function(callback)
- {
- var self = this;
-
- var model = {
- "id": this.getId(),
- "name": this.name,
- "schema": this.schema,
- "options": this.options,
- "view": this.view
- };
-
- // load items into array and store on model for future use
- self.createItems(function(items) {
-
- if (!items)
- {
- items = [];
- }
-
- // legacy support: assume containerItemEl = fieldEl
- for (var i = 0; i < items.length; i++)
- {
- if (!items[i].containerItemEl) {
- items[i].containerItemEl = items[i].getFieldEl();
- }
- }
-
- model.items = items;
-
- callback(model);
-
- });
- },
-
- /**
- * Called before the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- beforeRenderContainer: function(model, callback)
- {
- var self = this;
-
- callback();
- },
-
- /**
- * Renders the container into the field container.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- renderContainer: function(model, callback)
- {
- var container = null;
-
- if (this.containerDescriptor)
- {
- container = Alpaca.tmpl(this.containerDescriptor, model);
- }
-
- callback(container);
- },
-
- /**
- * Called after the container is rendered.
- *
- * @extension-point
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- self.beforeApplyCreatedItems(model, function() {
- self.applyCreatedItems(model, function () {
- self.afterApplyCreatedItems(model, function () {
- callback();
- });
- });
- });
- },
-
- /**
- * @see Alpaca.Field#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Field#initEvents
- */
- initEvents: function()
- {
- var self = this;
-
- this.base();
-
- /*
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
- */
- },
-
- /**
- * Creates any sub-items for this container.
- *
- * @extension_point
- *
- * @param callback
- */
- createItems: function(callback)
- {
- callback();
- },
-
- beforeApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.isTopLevel() && self.view.getLayout())
- {
- layoutBindings = self.view.getLayout().bindings;
-
- // if layout and bindings not provided, assume a default strategy
- if (!layoutBindings && self.view.getLayout().templateDescriptor && model.items.length > 0)
- {
- layoutBindings = {};
-
- for (var i = 0; i < model.items.length; i++)
- {
- var name = model.items[i].name;
-
- layoutBindings[name] = "[data-alpaca-layout-binding='" + name + "']";
- }
- }
-
- }
-
- if (model.items.length > 0)
- {
- $(self.container).addClass("alpaca-container-has-items");
- $(self.container).attr("data-alpaca-container-item-count", model.items.length);
- }
- else
- {
- $(self.container).removeClass("alpaca-container-has-items");
- $(self.container).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < model.items.length; i++)
- {
- var item = model.items[i];
-
- // find the insertion point
- var insertionPoint = $(self.container).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM + "[" + Alpaca.MARKER_DATA_CONTAINER_FIELD_ITEM_KEY + "='" + item.name + "']");
- if (!layoutBindings)
- {
- var holder = $(insertionPoint).parent();
-
- $(insertionPoint).replaceWith(item.containerItemEl);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- else
- {
- // use a layout
- var bindingId = layoutBindings[item.name];
- if (bindingId)
- {
- var holder = $(bindingId, self.field);
- if (holder.length == 0)
- {
- // legacy support, fallback to ID based
- try {
- holder = $('#' + bindingId, self.field);
- } catch (e) { }
- }
- if (holder.length > 0)
- {
- $(item.containerItemEl).appendTo(holder);
-
- // reset domEl to allow for refresh
- item.domEl = holder;
- }
- }
-
- // remove insertion point
- $(insertionPoint).remove();
- }
-
- $(item.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-first");
- }
-
- if (i + 1 === model.items.length)
- {
- $(item.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(item.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(item.containerItemEl).attr("data-alpaca-container-item-name", item.name);
- $(item.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
-
- // register the child
- self.registerChild(item, i);
- }
-
- if (self.options.collapsible)
- {
- // CALLBACK: "collapsible"
- self.fireCallback("collapsible");
- }
-
- self.triggerUpdate();
- callback();
- },
-
- afterApplyCreatedItems: function(model, callback)
- {
- callback();
- },
-
- /**
- * Helper method to add child field.
- *
- * @param {Alpaca.Control} child Child field to be added.
- * @param {Integer} index Index of the new child.
- */
- registerChild: function(child, index)
- {
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 0, child);
- }
- else
- {
- this.children.push(child);
- }
-
- this.childrenById[child.getId()] = child;
- if (child.propertyId)
- {
- this.childrenByPropertyId[child.propertyId] = child;
- }
-
- child.parent = this;
- },
-
- /**
- * Helper method to remove child field.
- *
- * @param index
- */
- unregisterChild: function(index)
- {
- var child = this.children[index];
- if (!child)
- {
- return;
- }
-
- if (!Alpaca.isEmpty(index))
- {
- this.children.splice(index, 1);
- }
-
- delete this.childrenById[child.getId()];
- if (child.propertyId)
- {
- delete this.childrenByPropertyId[child.propertyId];
- }
-
- child.parent = null;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updateChildDOMElements: function()
- {
- var self = this;
-
- var layoutBindings = null;
- if (self.view.getLayout()) {
- layoutBindings = self.view.getLayout().bindings;
- }
-
- if (!layoutBindings)
- {
- if (self.children.length > 0)
- {
- $(self.getContainerEl()).addClass("alpaca-container-has-items");
- $(self.getContainerEl()).attr("data-alpaca-container-item-count", self.children.length);
- }
- else
- {
- $(self.getContainerEl()).removeClass("alpaca-container-has-items");
- $(self.getContainerEl()).removeAttr("data-alpaca-container-item-count");
- }
-
- for (var i = 0; i < self.children.length; i++)
- {
- var child = self.children[i];
-
- // reset path and name
- child.path = self.path + "[" + i + "]";
- child.calculateName();
-
- $(child.containerItemEl).removeClass("alpaca-container-item-first");
- $(child.containerItemEl).removeClass("alpaca-container-item-last");
- $(child.containerItemEl).removeClass("alpaca-container-item-index");
- $(child.containerItemEl).removeClass("alpaca-container-item-key");
-
- $(child.containerItemEl).addClass("alpaca-container-item");
-
- if (i === 0)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-first");
- }
- if (i + 1 === self.children.length)
- {
- $(child.containerItemEl).addClass("alpaca-container-item-last");
- }
-
- $(child.containerItemEl).attr("data-alpaca-container-item-index", i);
- $(child.containerItemEl).attr("data-alpaca-container-item-name", child.name);
- $(child.containerItemEl).attr("data-alpaca-container-item-parent-field-id", self.getId());
- }
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentReveal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentReveal();
- }
- },
-
- /**
- * Propagates signal down to all children.
- * @override
- */
- onDependentConceal: function()
- {
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].onDependentConceal();
- }
- },
-
- /**
- * Focus an element in the container. Find the first invalid element or if no invalid elements, pick
- * the first child.
- */
- focus: function()
- {
- this.base();
-
- var index = -1;
-
- for (var i = 0; i < this.children.length; i++)
- {
- if (!this.children[i].isValid(true))
- {
- index = i;
- break;
- }
- }
- if (index === -1 && this.children.length > 0)
- {
- index = 0;
- }
-
- if (index > -1)
- {
- this.children[index].focus();
- }
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].disable();
- }
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.base();
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].enable();
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.Field#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "lazyLoading": {
- "title": "Lazy Loading",
- "description": "Child fields will only be rendered when the fieldset is expanded if this option is set true.",
- "type": "boolean",
- "default": false
- },
- "collapsible": {
- "title": "Collapsible",
- "description": "Field set is collapsible if true.",
- "type": "boolean",
- "default": true
- },
- "collapsed": {
- "title": "Collapsed",
- "description": "Field set is initially collapsed if true.",
- "type": "boolean",
- "default": false
- },
- "legendStyle": {
- "title": "Legend Style",
- "description": "Field set legend style.",
- "type": "string",
- "enum":["button","link"],
- "default": "button"
- },
- "animate": {
- "title": "Animate movements and transitions",
- "description": "Up and down transitions will be animated",
- "type": "boolean",
- "default": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Field#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "lazyLoading": {
- "rightLabel": "Lazy loading child fields ?",
- "helper": "Lazy loading will be enabled if checked.",
- "type": "checkbox"
- },
- "collapsible": {
- "rightLabel": "Field set collapsible ?",
- "helper": "Field set is collapsible if checked.",
- "type": "checkbox"
- },
- "collapsed": {
- "rightLabel": "Field set initially collapsed ?",
- "description": "Field set is initially collapsed if checked.",
- "type": "checkbox"
- },
- "legendStyle": {
- "type":"select"
- },
- "animate": {
- "rightLabel": "Animate movements and transitions",
- "type": "checkbox"
- }
- }
- });
- }
- /* end_builder_helpers */
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Connector = Base.extend(
- /**
- * @lends Alpaca.Connector.prototype
- */
- {
- /**
- * @constructs
- * @class Connects Alpaca to remote data stores.
-
- * @param {String} id Connector ID.
- */
- constructor: function(id)
- {
- this.id = id;
-
- // helper function to determine if a resource is a uri
- this.isUri = function(resource)
- {
- return !Alpaca.isEmpty(resource) && Alpaca.isUri(resource);
- };
-
- var ONE_HOUR = 3600000;
- this.cache = new AjaxCache('URL', true, ONE_HOUR);
- },
-
- /**
- * Makes initial connections to data source.
- *
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- connect: function (onSuccess, onError)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess();
- }
- },
-
- /**
- * Loads a template (HTML or Text).
- *
- * If the source is a URI, then it is loaded.
- * If it is not a URI, then the source is simply handed back.
- *
- * @param {Object|String} source Source to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadTemplate : function (source, onSuccess, onError)
- {
- if (!Alpaca.isEmpty(source))
- {
- if (Alpaca.isUri(source))
- {
- this.loadUri(source, false, function(loadedData) {
-
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loadedData);
- }
-
- }, function (loadError) {
-
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- });
- }
- else
- {
- onSuccess(source);
- }
- }
- else
- {
- onError({
- "message":"Empty data source.",
- "reason": "TEMPLATE_LOADING_ERROR"
- });
- }
- },
-
- /**
- * Loads JSON data.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback
- * @param {Function} onError onError callback
- */
- loadData: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads JSON view.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadView: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads schema, form, view and data in a single call.
- *
- * @param {Object} resources resources
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadAll: function (resources, onSuccess, onError)
- {
- var dataSource = resources.dataSource;
- var schemaSource = resources.schemaSource;
- var optionsSource = resources.optionsSource;
- var viewSource = resources.viewSource;
-
- // we allow "schema" to contain a URI as well (backwards-compatibility)
- if (!schemaSource)
- {
- schemaSource = resources.schema;
- }
-
- // we allow "options" to contain a URI as well (backwards-compatibility)
- if (!optionsSource)
- {
- optionsSource = resources.options;
- }
-
- // we allow "view" to contain a URI as well (backwards-compatibility)
- if (!viewSource)
- {
- viewSource = resources.view;
- }
-
- var loaded = {};
-
- var loadCounter = 0;
- var invocationCount = 0;
-
- var successCallback = function()
- {
- if (loadCounter === invocationCount)
- {
- if (onSuccess && Alpaca.isFunction(onSuccess))
- {
- onSuccess(loaded.data, loaded.options, loaded.schema, loaded.view);
- }
- }
- };
-
- var errorCallback = function (loadError)
- {
- if (onError && Alpaca.isFunction(onError))
- {
- onError(loadError);
- }
- };
-
- // count out the total # of invokes we're going to fire off
- if (dataSource)
- {
- invocationCount++;
- }
- if (schemaSource)
- {
- invocationCount++;
- }
- if (optionsSource)
- {
- invocationCount++;
- }
- if (viewSource)
- {
- invocationCount++;
- }
- if (invocationCount === 0)
- {
- // nothing to invoke, so just hand back
- successCallback();
- return;
- }
-
- // fire off all of the invokes
- if (dataSource)
- {
- this.loadData(dataSource, function(data) {
- loaded.data = data;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (schemaSource)
- {
- this.loadSchema(schemaSource, function(schema) {
- loaded.schema = schema;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (optionsSource)
- {
- this.loadOptions(optionsSource, function(options) {
- loaded.options = options;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- if (viewSource)
- {
- this.loadView(viewSource, function(view) {
- loaded.view = view;
- loadCounter++;
- successCallback();
- }, errorCallback);
- }
- },
-
- /**
- * Loads a JSON through Ajax call.
- *
- * @param {String} uri location of the json document
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadJson : function(uri, onSuccess, onError) {
- this.loadUri(uri, true, onSuccess, onError);
- } ,
-
- /**
- * Loads a general document through Ajax call.
- *
- * This uses jQuery to perform the Ajax call. If you need to customize connectivity to your own remote server,
- * this would be the appropriate place to do so.
- *
- * @param {String} uri uri to be loaded
- * @param {Boolean} isJson Whether the document is a JSON or not.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadUri : function(uri, isJson, onSuccess, onError) {
-
- var self = this;
-
- var ajaxConfigs = {
- "url": uri,
- "type": "get",
- "success": function(jsonDocument) {
-
- self.cache.put(uri, jsonDocument);
-
- if (onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(jsonDocument);
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
- if (onError && Alpaca.isFunction(onError)) {
- onError({
- "message":"Unable to load data from uri : " + uri,
- "stage": "DATA_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- }
- };
-
- if (isJson) {
- ajaxConfigs.dataType = "json";
- } else {
- ajaxConfigs.dataType = "text";
- }
-
- var cachedDocument = self.cache.get(uri);
-
- if (cachedDocument !== false && onSuccess && Alpaca.isFunction(onSuccess)) {
- onSuccess(cachedDocument);
- } else {
- $.ajax(ajaxConfigs);
- }
- },
-
- /**
- * Loads referenced JSON schema.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceSchema: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- /**
- * Loads referenced JSON options.
- *
- * @param {Object|String} resource Resource to be loaded.
- * @param {Function} onSuccess onSuccess callback.
- * @param {Function} onError onError callback.
- */
- loadReferenceOptions: function (resource, successCallback, errorCallback)
- {
- return this._handleLoadJsonResource(resource, successCallback, errorCallback);
- },
-
- _handleLoadJsonResource: function (resource, successCallback, errorCallback)
- {
- if (this.isUri(resource))
- {
- this.loadJson(resource, function(loadedResource) {
- successCallback(loadedResource);
- }, errorCallback);
- }
- else
- {
- successCallback(resource);
- }
- }
-
- });
-
- Alpaca.registerConnectorClass("default", Alpaca.Connector);
-
-
-
-
-
-
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // AJAX CACHE
- //
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
- /*!
- * ajax-cache JavaScript Library v0.2.1
- * http://code.google.com/p/ajax-cache/
- *
- * Includes few JSON methods (open source)
- * http://www.json.org/js.html
- *
- * Date: 2010-08-03
- */
- var AjaxCache = function AjaxCache(type, on, lifetime) {
- if (on) {
- this.on = true;
- } else {
- this.on = false;
- }
-
- // set default cache lifetime
- if (lifetime != null) {
- this.defaultLifetime = lifetime;
- }
-
- // set type
- this.type = type;
-
- // set cache functions according to type
- switch (this.type) {
- case 'URL':
- this.put = this.put_url;
- break;
- case 'GET':
- this.put = this.put_GET;
- break;
- }
-
- };
-
- AjaxCache.prototype.on = false;
- AjaxCache.prototype.type = undefined;
- AjaxCache.prototype.defaultLifetime = 1800000; // 1800000=30min, 300000=5min, 30000=30sec
- AjaxCache.prototype.items = {};
-
- /**
- * Caches the request and its response. Type: url
- *
- * @param url - url of ajax response
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_url = function(url, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Caches the request and its response. Type: GET
- *
- * @param url - url of ajax response
- * @param data - data params (query)
- * @param response - ajax response
- * @param lifetime - (optional) sets cache lifetime in miliseconds
- * @return true on success
- */
- AjaxCache.prototype.put_GET = function(url, data, response, lifetime) {
- if (lifetime == null) {
- lifetime = this.defaultLifetime;
- }
- var key = this.make_key(url, [ data ]);
- this.items[key] = {};
- this.items[key].key = key;
- this.items[key].url = url;
- this.items[key].data = data;
- this.items[key].response = response;
- this.items[key].expire = (new Date().getTime()) + lifetime;
- return true;
- };
-
- /**
- * Get cached ajax response
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return ajax response or false if such does not exist or is expired
- */
- AjaxCache.prototype.get = function(url, params) {
- var key = this.make_key(url, params);
-
- // if cache does not exist
- if (this.items[key] == null) {
- return false;
- }
-
- // if cache expired
- if (this.items[key].expire < (new Date().getTime())) {
- return false;
- }
-
- // everything is passed - lets return the response
- return this.items[key].response;
- };
-
- /**
- * Make unique key for each request depending on url and additional parameters
- *
- * @param url - url of ajax response
- * @param params - Array of additional parameters, to make key
- * @return unique key
- */
- AjaxCache.prototype.make_key = function(url, params) {
- var key = url;
- switch (this.type) {
- case 'URL':
- break;
- case 'GET':
- key += this.stringify(params[0]);
- break;
- }
-
- return key;
- };
-
- /**
- * Flush cache
- *
- * @return true on success
- */
- AjaxCache.prototype.flush = function() {
- // flush all cache
- cache.items = {};
- return true;
- };
-
- /*
- * Methods to stringify JavaScript/JSON objects.
- *
- * Taken from: http://www.json.org/js.html to be more exact, this file:
- * http://www.json.org/json2.js copied on 2010-07-19
- *
- * Taken methods: stringify, quote and str
- *
- * Methods are slightly modified to best fit ajax-cache functionality
- *
- */
- AjaxCache.prototype.stringify = function(value, replacer, space) {
-
- // The stringify method takes a value and an optional replacer, and an
- // optional
- // space parameter, and returns a JSON text. The replacer can be a function
- // that can replace values, or an array of strings that will select the
- // keys.
- // A default replacer method can be provided. Use of the space parameter can
- // produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
- // If the space parameter is a number, make an indent string containing that
- // many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
- // If the space parameter is a string, it will be used as the indent
- // string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
- // If there is a replacer, it must be a function or an array.
- // Otherwise, throw an error.
-
- rep = replacer;
- if (replacer &&
- typeof replacer !== 'function' &&
- (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
- // Make a fake root object containing our value under the key of ''.
- // Return the result of stringifying the value.
-
- return this.str('', {
- '' : value
- });
- };
-
- AjaxCache.prototype.quote = function(string) {
-
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe escape
- // sequences.
-
- var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable,
- function(a) {
- var c = meta[a];
- return typeof c === 'string' ? c : '\\u' + ('0000' + a
- .charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- };
-
- AjaxCache.prototype.str = function(key, holder) {
-
- // Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length, mind = gap, partial, value = holder[key];
-
- // If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value &&
- typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
- // If we were called with a replacer function, then call the replacer to
- // obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
- // What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return this.quote(value);
-
- case 'number':
-
- // JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
- // If the value is a boolean or null, convert it to a string. Note:
- // typeof null does not produce 'null'. The case is included here in
- // the remote chance that this gets fixed someday.
-
- return String(value);
-
- // If the type is 'object', we might be dealing with an object or an
- // array or
- // null.
-
- case 'object':
-
- // Due to a specification blunder in ECMAScript, typeof null is
- // 'object',
- // so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
- // Make an array to hold the partial results of stringifying this object
- // value.
-
- gap += indent;
- partial = [];
-
- // Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
- // The value is an array. Stringify every element. Use null as a
- // placeholder
- // for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = this.str(i, value) || 'null';
- }
-
- // Join all of the elements together, separated with commas, and
- // wrap them in
- // brackets.
-
- v = partial.length === 0 ? '[]' : gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
- // If the replacer is an array, use it to select the members to be
- // stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
- // Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = this.str(k, value);
- if (v) {
- partial.push(this.quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
- // Join all of the member texts together, separated with commas,
- // and wrap them in braces.
-
- v = partial.length === 0 ?
- '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- };
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Form = Base.extend(
- /**
- * @lends Alpaca.Form.prototype
- */
- {
- /**
- * @constructs
- *
- * @class This class is for managing HTML form control.
- *
- * @param {Object} container Field container.
- * @param {Object} options Field options.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(domEl, options, viewId, connector, errorCallback) {
-
- // container
- this.domEl = domEl;
-
- // parent
- this.parent = null;
-
- this.connector = connector;
- this.errorCallback = errorCallback;
-
- // options
- this.options = options;
-
- if (this.options.attributes)
- {
- this.attributes = this.options.attributes;
- }
- else
- {
- this.attributes = {};
- }
-
- if (this.options.buttons)
- {
- if (this.options.buttons.submit)
- {
- if (!this.options.buttons.submit.type)
- {
- this.options.buttons.submit.type = 'submit';
- }
-
- if (!this.options.buttons.submit.name)
- {
- this.options.buttons.submit.name = 'submit';
- }
-
- if (!this.options.buttons.submit.value)
- {
- this.options.buttons.submit.value = 'Submit';
- }
- }
-
- if (this.options.buttons.reset)
- {
- if (!this.options.buttons.reset.type)
- {
- this.options.buttons.reset.type = 'reset';
- }
- if (!this.options.buttons.reset.name)
- {
- this.options.buttons.reset.name = 'reset';
- }
- if (!this.options.buttons.reset.value)
- {
- this.options.buttons.reset.value = 'Reset';
- }
- }
-
- // some general correction
- for (var k in this.options.buttons)
- {
- if (this.options.buttons[k].label)
- {
- this.options.buttons[k].value = this.options.buttons[k].label;
- }
- if (this.options.buttons[k].title)
- {
- this.options.buttons[k].value = this.options.buttons[k].title;
- }
- if (!this.options.buttons[k].type)
- {
- this.options.buttons[k].type = "button";
- }
- }
- }
-
- if (this.attributes.id)
- {
- this.id = this.attributes.id;
- }
- else
- {
- this.id = Alpaca.generateId();
- this.attributes.id = this.id;
- }
-
- // if we have a submit button specified, and toggleSubmitValidState isn't defined, set to true by default
- // don't allow the form to submit unless valid
- if (this.options.buttons && this.options.buttons.submit && Alpaca.isUndefined(this.options.toggleSubmitValidState))
- {
- this.options.toggleSubmitValidState = true;
- }
-
- this.viewType = options.viewType;
-
- // set a runtime view
- this.view = new Alpaca.RuntimeView(viewId, this);
- },
-
- /**
- * Renders this form into the container.
- *
- * @param {Function} callback
- */
- render: function(callback)
- {
- var self = this;
-
- // remove the previous form element if it exists
- if (this.form)
- {
- this.form.remove();
- }
-
- // load the appropriate template and render it
- this.processRender(this.domEl, function() {
-
- // bind our field dom element into the container
- self.form.appendTo(self.container);
-
- // add default class
- self.form.addClass("alpaca-form");
-
- // CALLBACK: "form"
- self.fireCallback("form");
-
- // execute callback
- callback(self);
- });
- },
-
- /**
- * Determines whether the top control is entirely valid.
- *
- * @return {*}
- */
- isFormValid: function()
- {
- // re-compute validation for the full control set
- this.topControl.validate(true);
-
- var valid = this.topControl.isValid(true);
- //this.refreshValidationState(true);
-
- return valid;
- },
-
- isValid: function()
- {
- return this.isFormValid();
- },
-
- validate: function(children)
- {
- return this.topControl.validate(children);
- },
-
- enableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", false);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- disableSubmitButton: function()
- {
- $(".alpaca-form-button-submit").attrProp("disabled", true);
-
- if ($.mobile)
- {
- try { $(".alpaca-form-button-submit").button('refresh'); } catch (e) { }
- }
- },
-
- adjustSubmitButtonState: function()
- {
- this.disableSubmitButton();
-
- if (this.isFormValid())
- {
- this.enableSubmitButton();
- }
- },
-
- /**
- * Responsible for fetching any templates needed so as to render the
- * current mode for this field.
- *
- * Once completed, the onSuccess method is called.
- *
- * @param {Object} parentEl Field container.
- * @param {Function} callback
- */
- processRender: function(parentEl, callback)
- {
- var self = this;
-
- // lookup the template we should use to render
- this.formDescriptor = this.view.getTemplateDescriptor("form");
- if (!this.formDescriptor)
- {
- return Alpaca.throwErrorWithCallback("Could not find template descriptor: form");
- }
-
- var renderedDomElement = Alpaca.tmpl(this.formDescriptor, {
- id: this.getId(),
- options: this.options,
- view: this.view
- });
- renderedDomElement.appendTo(parentEl);
-
- this.form = renderedDomElement;
-
- // find our insertion point
- // this is marked by the handlebars helper
- this.formFieldsContainer = $(this.form).find("." + Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
- this.formFieldsContainer.removeClass(Alpaca.MARKER_CLASS_FORM_ITEMS_FIELD);
-
- if (Alpaca.isEmpty(this.form.attr("id")))
- {
- this.form.attr("id", this.getId() + "-form-outer");
- }
- if (Alpaca.isEmpty(this.form.attr("data-alpaca-form-id")))
- {
- this.form.attr("data-alpaca-form-id", this.getId());
- }
-
- // the form field
- parentEl.find("form").attr(this.attributes);
-
- // populate the buttons as well
- this.buttons = {};
- $(parentEl).find(".alpaca-form-button").each(function() {
-
- $(this).click(function(e) {
- $(this).attr("button-pushed", true);
- });
-
- // custom click handler?
- var key = $(this).attr("data-key");
- if (key)
- {
- var buttonConfig = self.options.buttons[key];
- if (buttonConfig)
- {
- if (buttonConfig.click)
- {
- $(this).click(function(form, handler) {
- return function(e) {
- e.preventDefault();
- handler.call(form, e);
- }
- }(self, buttonConfig.click));
- }
- }
- }
- });
-
- callback();
- },
-
- /**
- * Returns the id of the form.
- *
- * @returns {String} Form id
- */
- getId: function()
- {
- return this.id;
- },
-
- /**
- * Returns form type.
- *
- * @returns {String} Form type.
- */
- getType: function()
- {
- return this.type;
- },
-
- /**
- * Returns this form's parent.
- *
- * @returns {Object} Form parent.
- */
- getParent: function()
- {
- return this.parent;
- },
-
- /**
- * Returns the value of the JSON rendered by this form.
- *
- * @returns {Any} Value of the JSON rendered by this form.
- */
- getValue: function()
- {
- return this.topControl.getValue();
- },
-
- /**
- * Sets the value of the JSON to be rendered by this form.
- *
- * @param {Any} value Value to be set.
- */
- setValue: function(value)
- {
- this.topControl.setValue(value);
- },
-
- /**
- * Initializes events handling (Form Submission) for this form.
- */
- initEvents: function()
- {
- var _this = this;
-
- var formTag = $(this.domEl).find("form");
-
- var v = this.getValue();
- $(formTag).submit(v, function(e) {
- return _this.onSubmit(e, _this);
- });
-
- // listen for fieldupdates and determine whether the form is valid.
- // if so, enable the submit button...
- // otherwise, disable it
- if (this.options.toggleSubmitValidState)
- {
- $(_this.topControl.getFieldEl()).bind("fieldupdate", function() {
- _this.adjustSubmitButtonState();
- });
-
- this.adjustSubmitButtonState();
- }
- },
-
- getButtonEl: function(buttonId)
- {
- return $(this.domEl).find(".alpaca-form-button-" + buttonId);
- },
-
- /**
- * Handles form submit events.
- *
- * @param {Object} e Submit event.
- * @param {Object} form the form
- */
- onSubmit: function(e, form)
- {
- if (this.submitHandler)
- {
- e.stopPropagation();
-
- var v = this.submitHandler(e, form);
- if (Alpaca.isUndefined(v)) {
- v = false;
- }
-
- return v;
- }
- },
-
- /**
- * Registers a custom submit handler.
- *
- * @param {Object} func Submit handler to be registered.
- */
- registerSubmitHandler: function (func)
- {
- if (Alpaca.isFunction(func))
- {
- this.submitHandler = func;
- }
- },
-
- /**
- * Displays validation information of all fields of this form.
- *
- * @param {Boolean} children whether to render validation state for child fields
- *
- * @returns {Object} Form validation state.
- */
- refreshValidationState: function(children, callback)
- {
- this.topControl.refreshValidationState(children, callback);
- },
-
- /**
- * Disables this form.
- */
- disable: function()
- {
- this.topControl.disable();
- },
-
- /**
- * Enables this form.
- */
- enable: function()
- {
- this.topControl.enable();
- },
-
- /**
- * Focuses on this form.
- */
- focus: function()
- {
- this.topControl.focus();
- },
-
- /**
- * Purge any event listeners and remove the form from the DOM.
- *
- * @param [Boolean] skipParent when true, the form cleans up without traversing through parent child controls
- */
- destroy: function(skipParent)
- {
- this.getFormEl().remove();
-
- // we allow form.destroy() which tells parent control to destroy
- // if skipParent == true, then we do not call up (invoked from container)
- if (!skipParent && this.parent)
- {
- this.parent.destroy();
- }
- },
-
- /**
- * Shows the form.
- */
- show: function()
- {
- this.getFormEl().css({
- "display": ""
- });
- },
-
- /**
- * Hides the form.
- */
- hide: function()
- {
- this.getFormEl().css({
- "display": "none"
- });
- },
-
- /**
- * Clears the form and resets values of its fields.
- *
- * @param stopUpdateTrigger If false, triggers the update event of this event.
- */
- clear: function(stopUpdateTrigger)
- {
- this.topControl.clear(stopUpdateTrigger);
- },
-
- /**
- * Checks if form is empty.
- *
- * @returns {Boolean} True if the form is empty, false otherwise.
- */
- isEmpty: function()
- {
- return this.topControl.isEmpty();
- },
-
- /**
- * Fires a view callback for the current form.
- *
- * @param id
- * @param arg1
- * @param arg2
- * @param arg3
- * @param arg4
- * @param arg5
- */
- fireCallback: function(id, arg1, arg2, arg3, arg4, arg5)
- {
- this.view.fireCallback(this, id, arg1, arg2, arg3, arg4, arg5);
- },
-
- /**
- * Retrieves the form element.
- *
- * @returns {Object} The rendered DOM element.
- */
- getFormEl: function() {
- return this.form;
- },
-
- /**
- * Performs a regular old submit.
- */
- submit: function()
- {
- this.form.submit();
- },
-
- /**
- * Fires the submit in the background and hands back the jQuery promise.
- *
- * @returns {*}
- */
- ajaxSubmit: function()
- {
- var self = this;
-
- return $.ajax({
- data: this.getValue(),
- url: self.options.attributes.action,
- type: self.options.attributes.method,
- dataType: "json"
- });
- }
-
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.TextField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "text";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
-
- /*
- if (!this.options.size) {
- this.options.size = 40;
- }
- */
-
- // assume html5 input type = "text"
- if (!this.inputType)
- {
- this.inputType = "text";
- }
-
- if (this.options.inputType)
- {
- this.inputType = this.options.inputType;
- }
-
- // DOM data-* attributes support
- if (!this.options.data)
- {
- this.options.data = {};
- }
-
- // DOM * attributes support
- if (!this.options.attributes)
- {
- this.options.attributes = {};
- }
-
- if (typeof(this.options.allowOptionalEmpty) == "undefined")
- {
- this.options.allowOptionalEmpty = true;
- }
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- this.base();
-
- // clean up typeahead
- if ( this.control && this.control.typeahead && this.options.typeahead)
- {
- $(this.control).typeahead('destroy');
- }
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- if (self.control)
- {
- // mask
- self.applyMask();
-
- // typeahead
- self.applyTypeAhead();
-
- // update max length indicator
- self.updateMaxLengthIndicator();
- }
-
- callback();
- });
- },
-
- applyMask: function()
- {
- var self = this;
-
- // mask it
- if (self.control.mask && self.options.maskString)
- {
- self.control.mask(self.options.maskString);
- }
- },
-
- applyTypeAhead: function()
- {
- var self = this;
-
- if (self.control.typeahead && self.options.typeahead && !Alpaca.isEmpty(self.options.typeahead))
- {
- var tConfig = self.options.typeahead.config;
- if (!tConfig) {
- tConfig = {};
- }
-
- var tDatasets = self.options.typeahead.datasets;
- if (!tDatasets) {
- tDatasets = {};
- }
-
- if (!tDatasets.name) {
- tDatasets.name = self.getId();
- }
-
- var tEvents = self.options.typeahead.events;
- if (!tEvents) {
- tEvents = {};
- }
-
- // support for each datasets (local, remote, prefetch)
- if (tDatasets.type === "local" || tDatasets.type === "remote" || tDatasets.type === "prefetch")
- {
- var bloodHoundConfig = {
- datumTokenizer: function(d) {
- return Bloodhound.tokenizers.whitespace(d.value);
- },
- queryTokenizer: Bloodhound.tokenizers.whitespace
- };
-
- if (tDatasets.type === "local" )
- {
- var local = [];
-
- if (typeof(tDatasets.source) === "function")
- {
- bloodHoundConfig.local = tDatasets.source;
- }
- else
- {
- // array
- for (var i = 0; i < tDatasets.source.length; i++)
- {
- var localElement = tDatasets.source[i];
- if (typeof(localElement) === "string")
- {
- localElement = {
- "value": localElement
- };
- }
-
- local.push(localElement);
- }
-
- bloodHoundConfig.local = local;
- }
-
- if (tDatasets.local)
- {
- bloodHoundConfig.local = tDatasets.local;
- }
- }
-
- if (tDatasets.type === "prefetch")
- {
- bloodHoundConfig.prefetch = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.prefetch.filter = tDatasets.filter;
- }
- }
-
- if (tDatasets.type === "remote")
- {
- bloodHoundConfig.remote = {
- url: tDatasets.source
- };
-
- if (tDatasets.filter)
- {
- bloodHoundConfig.remote.filter = tDatasets.filter;
- }
-
- if (tDatasets.replace)
- {
- bloodHoundConfig.remote.replace = tDatasets.replace;
- }
- }
-
- var engine = new Bloodhound(bloodHoundConfig);
- engine.initialize();
- tDatasets.source = engine.ttAdapter();
- }
-
- // compile templates
- if (tDatasets.templates)
- {
- for (var k in tDatasets.templates)
- {
- var template = tDatasets.templates[k];
- if (typeof(template) === "string")
- {
- tDatasets.templates[k] = Handlebars.compile(template);
- }
- }
- }
-
- // process typeahead
- $(self.control).typeahead(tConfig, tDatasets);
-
- // listen for "autocompleted" event and set the value of the field
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // listen for "selected" event and set the value of the field
- $(self.control).on("typeahead:selected", function(event, datum) {
- self.setValue(datum.value);
- $(self.control).change();
- });
-
- // custom events
- if (tEvents)
- {
- if (tEvents.autocompleted) {
- $(self.control).on("typeahead:autocompleted", function(event, datum) {
- tEvents.autocompleted(event, datum);
- });
- }
- if (tEvents.selected) {
- $(self.control).on("typeahead:selected", function(event, datum) {
- tEvents.selected(event, datum);
- });
- }
- }
-
- // when the input value changes, change the query in typeahead
- // this is to keep the typeahead control sync'd with the actual dom value
- // only do this if the query doesn't already match
- var fi = $(self.control);
- $(self.control).change(function() {
-
- var value = $(this).val();
-
- var newValue = $(fi).typeahead('val');
- if (newValue !== value)
- {
- $(fi).typeahead('val', newValue);
- }
-
- });
-
- // some UI cleanup (we don't want typeahead to restyle)
- $(self.field).find("span.twitter-typeahead").first().css("display", "block"); // SPAN to behave more like DIV, next line
- $(self.field).find("span.twitter-typeahead input.tt-input").first().css("background-color", "");
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.inputType = self.inputType;
-
- callback(model);
- });
- },
-
- updateMaxLengthIndicator: function()
- {
- var self = this;
-
- var errState = false;
-
- var message = "";
- if (!Alpaca.isEmpty(self.schema.maxLength) && self.options.showMaxLengthIndicator)
- {
- var val = self.getValue() || "";
-
- var diff = self.schema.maxLength - val.length;
- if (diff >= 0)
- {
- message = "You have " + diff + " characters remaining";
- }
- else
- {
- message = "Your message is too long by " + (diff*-1) + " characters";
- errState = true;
- }
-
- var indicator = $(self.field).find(".alpaca-field-text-max-length-indicator");
- if (indicator.length === 0)
- {
- indicator = $("");
- $(self.control).after(indicator);
- }
-
- $(indicator).html(message);
- $(indicator).removeClass("err");
- if (errState)
- {
- $(indicator).addClass("err");
- }
- }
-
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!this.isDisplayOnly() && this.control && this.control.length > 0)
- {
- value = this._getControlVal(true);
-
- if (self.control.mask && self.options.maskString)
- {
- // get unmasked value
- var fn = $(this.control).data($.mask.dataName);
- if (fn)
- {
- value = fn();
- value = self.ensureProperType(value);
- }
- }
- }
- else
- {
- value = this.base();
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (this.control && this.control.length > 0)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
- }
-
- // be sure to call into base method
- this.base(value);
-
- // if applicable, update the max length indicator
- this.updateMaxLengthIndicator();
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validatePattern();
- valInfo["invalidPattern"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidPattern"), [this.schema.pattern]),
- "status": status
- };
-
- status = this._validateMaxLength();
- valInfo["stringTooLong"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooLong"), [this.schema.maxLength]),
- "status": status
- };
-
- status = this._validateMinLength();
- valInfo["stringTooShort"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringTooShort"), [this.schema.minLength]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidPattern"]["status"] && valInfo["stringTooLong"]["status"] && valInfo["stringTooShort"]["status"];
- },
-
- /**
- * Validates against the schema pattern property.
- *
- * @returns {Boolean} True if it matches the pattern, false otherwise.
- */
- _validatePattern: function()
- {
- if (this.schema.pattern)
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (!val.match(this.schema.pattern))
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates against the schema minLength property.
- *
- * @returns {Boolean} True if its size is greater than minLength, false otherwise.
- */
- _validateMinLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.minLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length < this.schema.minLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates against the schema maxLength property.
- *
- * @returns {Boolean} True if its size is less than maxLength , false otherwise.
- */
- _validateMaxLength: function()
- {
- if (!Alpaca.isEmpty(this.schema.maxLength))
- {
- var val = this.getValue();
- if (val === "" && this.options.allowOptionalEmpty && !this.isRequired())
- {
- return true;
- }
- if (Alpaca.isEmpty(val))
- {
- val = "";
- }
- if (val.length > this.schema.maxLength)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- if (this.control && this.control.length > 0)
- {
- // focuses the control and also positions the input at the end
-
- var el = $(this.control).get(0);
-
- try {
- var elemLen = el.value ? el.value.length : 0;
- el.selectionStart = elemLen;
- el.selectionEnd = elemLen;
- }
- catch (e) {
- // field type doesn't support selection start and end
- }
-
- el.focus();
- }
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyDown: function(e)
- {
- var self = this;
-
- if (e.keyCode === 8) // backspace
- {
- if (!Alpaca.isEmpty(self.schema.minLength) && (self.options.constrainLengths || self.options.constrainMinLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length <= self.schema.minLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- else
- {
- if (!Alpaca.isEmpty(self.schema.maxLength) && (self.options.constrainLengths || self.options.constrainMaxLength))
- {
- var newValue = self.getValue() || "";
- if (newValue.length >= self.schema.maxLength)
- {
- // kill event
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- }
- }
- },
-
- onKeyUp: function(e)
- {
- var self = this;
-
- // if applicable, update the max length indicator
- self.updateMaxLengthIndicator();
- }
-
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Single-Line Text";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Text field for single-line text.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minLength": {
- "title": "Minimal Length",
- "description": "Minimal length of the property value.",
- "type": "number"
- },
- "maxLength": {
- "title": "Maximum Length",
- "description": "Maximum length of the property value.",
- "type": "number"
- },
- "pattern": {
- "title": "Pattern",
- "description": "Regular expression for the property value.",
- "type": "string"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "default": {
- "helper": "Field default value",
- "type": "text"
- },
- "minLength": {
- "type": "integer"
- },
- "maxLength": {
- "type": "integer"
- },
- "pattern": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "size": {
- "title": "Field Size",
- "description": "Field size.",
- "type": "number",
- "default":40
- },
- "maskString": {
- "title": "Mask Expression",
- "description": "Expression for the field mask. Field masking will be enabled if not empty.",
- "type": "string"
- },
- "placeholder": {
- "title": "Field Placeholder",
- "description": "Field placeholder.",
- "type": "string"
- },
- "typeahead": {
- "title": "Type Ahead",
- "description": "Provides configuration for the $.typeahead plugin if it is available. For full configuration options, see: https://github.com/twitter/typeahead.js"
- },
- "allowOptionalEmpty": {
- "title": "Allow Optional Empty",
- "description": "Allows this non-required field to validate when the value is empty"
- },
- "inputType": {
- "title": "HTML5 Input Type",
- "description": "Allows for the override of the underlying HTML5 input type. If not specified, an assumed value is provided based on the kind of input control (i.e. 'text', 'date', 'email' and so forth)",
- "type": "string"
- },
- "data": {
- "title": "Data attributes for the underlying DOM input control",
- "description": "Allows you to specify a key/value map of data attributes that will be added as DOM attribuets for the underlying input control. The data attributes will be added as data-{name}='{value}'.",
- "type": "object"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "size": {
- "type": "integer"
- },
- "maskString": {
- "helper": "a - an alpha character;9 - a numeric character;* - an alphanumeric character",
- "type": "text"
- },
- "typeahead": {
- "type": "object"
- },
- "allowOptionalEmpty": {
- "type": "checkbox"
- },
- "inputType": {
- "type": "text"
- },
- "data": {
- "type": "object"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "invalidPattern": "This field should have pattern {0}",
- "stringTooShort": "This field should contain at least {0} numbers or characters",
- "stringTooLong": "This field should contain at most {0} numbers or characters"
- });
- Alpaca.registerFieldClass("text", Alpaca.Fields.TextField);
- Alpaca.registerDefaultSchemaFieldMapping("string", "text");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.TextAreaField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.TextAreaField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function()
- {
- return "textarea";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.options.rows) {
- this.options.rows = 5;
- }
-
- if (!this.options.cols) {
- this.options.cols = 40;
- }
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": status
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"];
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.data;
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Multi-Line Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Textarea field for multiple line text.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rows": {
- "title": "Rows",
- "description": "Number of rows",
- "type": "number",
- "default": 5
- },
- "cols": {
- "title": "Columns",
- "description": "Number of columns",
- "type": "number",
- "default": 40
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rows": {
- "type": "integer"
- },
- "cols": {
- "type": "integer"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded."
- });
-
- Alpaca.registerFieldClass("textarea", Alpaca.Fields.TextAreaField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CheckBoxField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.CheckBoxField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "checkbox";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function() {
-
- var _this = this;
-
- _this.base();
-
- if (!this.options.rightLabel) {
- this.options.rightLabel = "";
- }
-
- if (typeof(_this.options.multiple) == "undefined")
- {
- if (_this.schema.type === "array")
- {
- _this.options.multiple = true;
- }
- else if (typeof(_this.schema["enum"]) != "undefined")
- {
- _this.options.multiple = true;
- }
- }
-
- _this.checkboxOptions = [];
- if (_this.options.multiple)
- {
- $.each(_this.getEnum(), function(index, value) {
-
- var text = value;
-
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.checkboxOptions.push({
- "value": value,
- "text": text
- });
- });
- }
- },
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- var array = [];
-
- if (this.schema && this.schema["enum"])
- {
- array = this.schema["enum"];
- }
-
- return array;
- },
-
- /**
- * Handler for the event that the checkbox is clicked.
- *
- * @param e Event.
- */
- onClick: function(e)
- {
- this.refreshValidationState();
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
- model.checkboxOptions = self.checkboxOptions;
-
- callback(model);
- });
- },
-
- /**
- * @see Alpaca.ControlField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the checked state of the control to update
- if (self.data && typeof(self.data) !== "undefined")
- {
- self.setValue(self.data);
- }
-
- // whenever the state of one of our input:checkbox controls is changed (either via a click or programmatically),
- // we signal to the top-level field to fire up a change
- //
- // this allows the dependency system to recalculate and such
- //
- $(self.getFieldEl()).find("input:checkbox").change(function(evt) {
- self.triggerWithPropagation("change");
- });
-
- // for multiple mode, mark values
- if (self.options.multiple)
- {
- // none checked
- $(self.getFieldEl()).find("input:checkbox").prop("checked", false);
-
- if (self.data)
- {
- var dataArray = self.data;
- if (typeof(self.data) === "string")
- {
- dataArray = self.data.split(",");
- for (var a = 0; a < dataArray.length; a++)
- {
- dataArray[a] = $.trim(dataArray[a]);
- }
- }
-
- for (var k in dataArray)
- {
- $(self.getFieldEl()).find("input:checkbox[data-checkbox-value=\"" + dataArray[k] + "\"]").prop("checked", true);
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var value = null;
-
- if (!self.options.multiple)
- {
- // single scalar value
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- value = Alpaca.checked($(input[0]));
- }
- else
- {
- value = false;
- }
- }
- else
- {
- // multiple values
- var values = [];
- for (var i = 0; i < self.checkboxOptions.length; i++)
- {
- var inputField = $(self.getFieldEl()).find("input[data-checkbox-index='" + i + "']");
- if (Alpaca.checked(inputField))
- {
- var v = $(inputField).attr("data-checkbox-value");
- values.push(v);
- }
- }
-
- // determine how we're going to hand this value back
-
- // if type == "array", we just hand back the array
- // if type == "string", we build a comma-delimited list
- if (self.schema.type === "array")
- {
- value = values;
- }
- else if (self.schema.type === "string")
- {
- value = values.join(",");
- }
- }
-
- return value;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- // value can be a boolean, string ("true"), string ("a,b,c") or an array of values
-
- var applyScalarValue = function(value)
- {
- if (Alpaca.isString(value)) {
- value = (value === "true");
- }
-
- var input = $(self.getFieldEl()).find("input");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- };
-
- var applyMultiValue = function(values)
- {
- // allow for comma-delimited strings
- if (typeof(values) === "string")
- {
- values = values.split(",");
- }
-
- // trim things to remove any excess white space
- for (var i = 0; i < values.length; i++)
- {
- values[i] = Alpaca.trim(values[i]);
- }
-
- // walk through values and assign into appropriate inputs
- for (var j = 0; j < values.length; j++)
- {
- var input = $(self.getFieldEl()).find("input[data-checkbox-value=\"" + values[j] + "\"]");
- if (input.length > 0)
- {
- Alpaca.checked($(input[0]), value);
- }
- }
- };
-
- var applied = false;
-
- if (!self.options.multiple)
- {
- // single value mode
-
- // boolean
- if (typeof(value) === "boolean")
- {
- applyScalarValue(value);
- applied = true;
- }
- else if (typeof(value) === "string")
- {
- applyScalarValue(value);
- applied = true;
- }
- }
- else
- {
- // multiple value mode
-
- if (typeof(value) === "string")
- {
- applyMultiValue(value);
- applied = true;
- }
- else if (Alpaca.isArray(value))
- {
- applyMultiValue(value);
- applied = true;
- }
- }
-
- if (!applied && value)
- {
- Alpaca.logError("CheckboxField cannot set value for schema.type=" + self.schema.type + " and value=" + value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * Validate against enum property in the case that the checkbox field is in multiple mode.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var self = this;
-
- if (!self.options.multiple)
- {
- return true;
- }
-
- var val = self.getValue();
- if (!self.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- // if val is a string, convert to array
- if (typeof(val) === "string")
- {
- val = val.split(",");
- }
-
- return Alpaca.anyEquality(val, self.schema["enum"]);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = true;
- });
-
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- $(this.control).find("input").each(function() {
- $(this).disabled = false;
- });
-
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "boolean";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Checkbox Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Checkbox Field for boolean (true/false), string ('true', 'false' or comma-delimited string of values) or data array.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "rightLabel": {
- "title": "Option Label",
- "description": "Optional right-hand side label for single checkbox field.",
- "type": "string"
- },
- "multiple": {
- "title": "Multiple",
- "description": "Whether to render multiple checkboxes for multi-valued type (such as an array or a comma-delimited string)",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "rightLabel": {
- "type": "text"
- },
- "multiple": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("checkbox", Alpaca.Fields.CheckBoxField);
- Alpaca.registerDefaultSchemaFieldMapping("boolean", "checkbox");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.FileField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.FileField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "file";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- this.data = value;
-
- this.data = value;
-
- this.updateObservable();
-
- this.triggerUpdate();
- },
-
- getValue: function()
- {
- return this.data;
- },
-
- onChange: function(e)
- {
- this.base(e);
-
- if (this.options.selectionHandler)
- {
- this.processSelectionHandler(e.target.files);
- }
- },
-
- processSelectionHandler: function(files)
- {
- if (files && files.length > 0)
- {
- // if the browser supports HTML5 FileReader, we can pull in the stream for preview
- if (typeof(FileReader) !== "undefined")
- {
- // clear out previous loaded data
- var loadedData = [];
- var loadCount = 0;
-
- var fileReader = new FileReader();
- fileReader.onload = (function() {
- var field = this;
- return function(event)
- {
- var dataUri = event.target.result;
-
- loadedData.push(dataUri);
- loadCount++;
-
- if (loadCount === files.length)
- {
- field.options.selectionHandler.call(field, files, loadedData);
- }
- };
- }).call(this);
-
- for (var i = 0; i < files.length; i++)
- {
- fileReader.readAsDataURL(files[i]);
- }
- }
- }
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "File Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for uploading files.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "selectionHandler": {
- "title": "Selection Handler",
- "description": "Function that should be called when files are selected. Requires HTML5.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "selectionHandler": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("file", Alpaca.Fields.FileField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ListField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ListField.prototype
- */
- {
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- var _this = this;
-
- _this.base();
-
- _this.selectOptions = [];
-
- if (_this.getEnum())
- {
- $.each(_this.getEnum(), function(index, value)
- {
- var text = value;
- if (_this.options.optionLabels)
- {
- if (!Alpaca.isEmpty(_this.options.optionLabels[index]))
- {
- text = _this.options.optionLabels[index];
- }
- else if (!Alpaca.isEmpty(_this.options.optionLabels[value]))
- {
- text = _this.options.optionLabels[value];
- }
- }
-
- _this.selectOptions.push({
- "value": value,
- "text": text
- });
- });
- }
-
- /**
- * Auto assign data if we have data and the field is required and removeDefaultNone is either unspecified or true
- */
- if (_this.isRequired() && !_this.data)
- {
- //if ((typeof(_this.options.removeDefaultNone) == "undefined") || _this.options.removeDefaultNone === true)
- if ((_this.options.removeDefaultNone === true))
- {
- if (_this.schema.enum && _this.schema.enum.length > 0)
- {
- _this.data = _this.schema.enum[0];
- }
- }
- }
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.noneLabel = "None";
- if (typeof(self.options.noneLabel) != "undefined")
- {
- model.noneLabel = self.options.noneLabel;
- }
-
- model.hideNone = self.isRequired();
- if (typeof(self.options.removeDefaultNone) != "undefined")
- {
- model.hideNone = self.options.removeDefaultNone;
- }
-
- callback(model);
- });
- },
-
-
- /**
- * Gets schema enum property.
- *
- * @returns {Array|String} Field schema enum property.
- */
- getEnum: function()
- {
- if (this.schema && this.schema["enum"])
- {
- return this.schema["enum"];
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function(val)
- {
- var _this = this;
- if (Alpaca.isArray(val))
- {
- $.each(val, function(index, itemVal) {
- $.each(_this.selectOptions, function(index2, selectOption) {
-
- if (selectOption.value === itemVal)
- {
- val[index] = selectOption.value;
- }
-
- });
- });
- }
- else
- {
- $.each(this.selectOptions, function(index, selectOption) {
-
- if (selectOption.value === val)
- {
- val = selectOption.value;
- }
-
- });
- }
- return val;
- },
-
- /**
- * @see Alpaca.ControlField#beforeRenderControl
- */
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.options.dataSource)
- {
- self.selectOptions = [];
-
- var completionFunction = function()
- {
- self.schema.enum = [];
- self.options.optionLabels = [];
-
- for (var i = 0; i < self.selectOptions.length; i++)
- {
- self.schema.enum.push(self.selectOptions[i].value);
- self.options.optionLabels.push(self.selectOptions[i].text);
- }
-
- // push back to model
- model.selectOptions = self.selectOptions;
-
- callback();
- };
-
- if (Alpaca.isFunction(self.options.dataSource))
- {
- self.options.dataSource.call(self, function(values) {
-
- if (Alpaca.isArray(values))
- {
- for (var i = 0; i < values.length; i++)
- {
- if (typeof(values[i]) === "string")
- {
- self.selectOptions.push({
- "text": values[i],
- "value": values[i]
- });
- }
- else if (Alpaca.isObject(values[i]))
- {
- self.selectOptions.push(values[i]);
- }
- }
-
- completionFunction();
- }
- else if (Alpaca.isObject(values))
- {
- for (var k in values)
- {
- self.selectOptions.push({
- "text": k,
- "value": values[k]
- });
- }
-
- completionFunction();
- }
- else
- {
- completionFunction();
- }
- });
- }
- else if (Alpaca.isUri(self.options.dataSource))
- {
- $.ajax({
- url: self.options.dataSource,
- type: "get",
- dataType: "json",
- success: function(jsonDocument) {
-
- var ds = jsonDocument;
- if (self.options.dsTransformer && Alpaca.isFunction(self.options.dsTransformer))
- {
- ds = self.options.dsTransformer(ds);
- }
-
- if (ds)
- {
- if (Alpaca.isObject(ds))
- {
- // for objects, we walk through one key at a time
- // the insertion order is the order of the keys from the map
- // to preserve order, consider using an array as below
- $.each(ds, function(key, value) {
- self.selectOptions.push({
- "value": key,
- "text": value
- });
- });
-
- completionFunction();
- }
- else if (Alpaca.isArray(ds))
- {
- // for arrays, we walk through one index at a time
- // the insertion order is dictated by the order of the indices into the array
- // this preserves order
- $.each(ds, function(index, value) {
- self.selectOptions.push({
- "value": value.value,
- "text": value.text
- });
- });
-
- completionFunction();
- }
- }
- },
- "error": function(jqXHR, textStatus, errorThrown) {
-
- self.errorCallback({
- "message":"Unable to load data from uri : " + _this.options.dataSource,
- "stage": "DATASOURCE_LOADING_ERROR",
- "details": {
- "jqXHR" : jqXHR,
- "textStatus" : textStatus,
- "errorThrown" : errorThrown
- }
- });
- }
- });
- }
- else if (Alpaca.isArray(self.options.dataSource))
- {
- for (var i = 0; i < self.options.dataSource.length; i++)
- {
- if (typeof(self.options.dataSource[i]) === "string")
- {
- self.selectOptions.push({
- "text": self.options.dataSource[i],
- "value": self.options.dataSource[i]
- });
- }
- else if (Alpaca.isObject(self.options.dataSource[i]))
- {
- self.selectOptions.push(self.options.dataSource[i]);
- }
- }
-
- completionFunction();
- }
- else
- {
- callback();
- }
- }
- else
- {
- callback();
- }
-
- });
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "enum": {
- "title": "Enumeration",
- "description": "List of field value options",
- "type": "array",
- "required": true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "optionLabels": {
- "title": "Option Labels",
- "description": "Labels for options. It can either be a map object or an array field that maps labels to items defined by enum schema property one by one.",
- "type": "array"
- },
- "dataSource": {
- "title": "Option Datasource",
- "description": "Datasource for generating list of options. This can be a string or a function. If a string, it is considered to be a URI to a service that produces a object containing key/value pairs or an array of elements of structure {'text': '', 'value': ''}. This can also be a function that is called to produce the same list.",
- "type": "string"
- },
- "removeDefaultNone": {
- "title": "Remove Default None",
- "description": "If true, the default 'None' option will not be shown.",
- "type": "boolean",
- "default": false
- },
- "noneLabel": {
- "title": "None Label",
- "description": "The label to use for the 'None' option in a list (select, radio or otherwise).",
- "type": "string",
- "default": "None"
- },
- "hideNone": {
- "title": "Hide None",
- "description": "Whether to hide the None option from a list (select, radio or otherwise). This will be true if the field is required and false otherwise.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "optionLabels": {
- "itemLabel":"Label",
- "type": "array"
- },
- "dataSource": {
- "type": "text"
- },
- "removeDefaultNone": {
- "type": "checkbox",
- "rightLabel": "Remove Default None"
- },
- "noneLabel": {
- "type": "text"
- },
- "hideNone": {
- "type": "checkbox",
- "rightLabel": "Hide the 'None' option from the list"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-})(jQuery);
-
-(function($){
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.RadioField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.RadioField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "radio";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.options.name)
- {
- this.name = this.options.name;
- }
- else if (!this.name)
- {
- this.name = this.getId() + "-name";
- }
-
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.emptySelectFirst))
- {
- this.options.emptySelectFirst = false;
- }
-
- // assume vertical orientation
- // empty select first to false by default
- if (Alpaca.isUndefined(this.options.vertical))
- {
- this.options.vertical = true;
- }
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- var self = this;
-
- var val = null;
-
- $(this.control).find(":checked").each(function() {
- val = $(this).val();
-
- val = self.ensureProperType(val);
- });
-
- return val;
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- var self = this;
-
- // clear all
- $(this.control).find("input").each(function() {
- Alpaca.checked($(this), null);
- });
-
- // mark selected value
- if (typeof(val) != "undefined")
- {
- Alpaca.checked($(self.control).find("input[value=\"" + val + "\"]"), "checked");
- }
-
- // if none selected and "emptySelectFirst", then select
- if (this.options.emptySelectFirst)
- {
- if ($(this.control).find("input:checked").length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio").first(), "checked");
- }
- }
-
- this.base(val);
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- var inputs = $(this.control).find("input");
-
- inputs.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- inputs.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
- model.removeDefaultNone = self.options.removeDefaultNone;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
-
- if ($("input:radio:checked", self.control).length === 0)
- {
- Alpaca.checked($(self.control).find("input:radio[value=\"" + self.data + "\"]"), "checked");
- }
- }
-
- // stack radio selectors vertically
- if (self.options.vertical)
- {
- $(self.control).css("display", "block");
- }
- else
- {
- $(self.control).css("display", "inline-block");
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.ControlField#onClick
- */
- onClick: function(e)
- {
- this.base(e);
-
- var self = this;
-
- var val = $(e.currentTarget).find("input").val();
- if (typeof(val) != "undefined")
- {
- self.setValue(val);
- self.refreshValidationState();
- }
-
- /*
- Alpaca.later(25, this, function(){
- var v = self.getValue();
- self.setValue(v);
- self.refreshValidationState();
- });
- */
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Radio Group Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Radio Group Field with list of options.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function()
- {
- return Alpaca.merge(this.base(),{
- "properties": {
- "name": {
- "title": "Field name",
- "description": "Field name.",
- "type": "string"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "vertical": {
- "title": "Position the radio selector items vertically",
- "description": "By default, radio controls are stacked vertically. Set to false if you'd like radio controls to lay out horizontally.",
- "type": "boolean",
- "default": true
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("radio", Alpaca.Fields.RadioField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SelectField = Alpaca.Fields.ListField.extend(
- /**
- * @lends Alpaca.Fields.SelectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function()
- {
- return "select";
- },
-
- /**
- * @see Alpaca.Fields.ListField#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- if (this.control && this.control.length > 0)
- {
- var val = this._getControlVal(true);
- if (typeof(val) === "undefined")
- {
- val = this.data;
- }
-
- return this.base(val);
- }
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(val)
- {
- if (Alpaca.isArray(val))
- {
- if (!Alpaca.compareArrayContent(val, this.getValue()))
- {
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- else
- {
- if (val !== this.getValue())
- {
- /*
- if (!Alpaca.isEmpty(val) && this.control)
- {
- this.control.val(val);
- }
- */
- if (this.control && typeof(val) != "undefined" && val != null)
- {
- this.control.val(val);
- }
-
- this.base(val);
- }
- }
- },
-
- /**
- * @see Alpaca.ListField#getEnum
- */
- getEnum: function()
- {
- if (this.schema)
- {
- if (this.schema["enum"])
- {
- return this.schema["enum"];
- }
- else if (this.schema["type"] && this.schema["type"] === "array" && this.schema["items"] && this.schema["items"]["enum"])
- {
- return this.schema["items"]["enum"];
- }
- }
- },
-
- initControlEvents: function()
- {
- var self = this;
-
- self.base();
-
- if (self.options.multiple)
- {
- var button = this.control.parent().find("button.multiselect");
-
- button.focus(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onFocus.call(self, e);
- self.trigger("focus", e);
- }
- });
-
- button.blur(function(e) {
- if (!self.suspendBlurFocus)
- {
- self.onBlur.call(self, e);
- self.trigger("blur", e);
- }
- });
- }
- },
-
- beforeRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.schema["type"] && self.schema["type"] === "array")
- {
- self.options.multiple = true;
- }
-
- callback();
-
- });
- },
-
- prepareControlModel: function(callback)
- {
- var self = this;
-
- this.base(function(model) {
-
- model.selectOptions = self.selectOptions;
-
- callback(model);
- });
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // if emptySelectFirst and nothing currently checked, then pick first item in the value list
- // set data and visually select it
- if (Alpaca.isUndefined(self.data) && self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0)
- {
- self.data = self.selectOptions[0].value;
- }
-
- // do this little trick so that if we have a default value, it gets set during first render
- // this causes the state of the control
- if (self.data)
- {
- self.setValue(self.data);
- }
-
- // if we are in multiple mode and the bootstrap multiselect plugin is available, bind it in
- if (self.options.multiple && $.fn.multiselect)
- {
- var settings = null;
- if (self.options.multiselect) {
- settings = self.options.multiselect;
- }
- else
- {
- settings = {};
- }
- if (!settings.nonSelectedText)
- {
- settings.nonSelectedText = "None";
- if (self.options.noneLabel)
- {
- settings.nonSelectedText = self.options.noneLabel;
- }
- }
- if (self.options.hideNone)
- {
- delete settings.nonSelectedText;
- }
-
- $(self.getControlEl()).multiselect(settings);
- }
-
- callback();
-
- });
- },
-
- /**
- * Validate against enum property.
- *
- * @returns {Boolean} True if the element value is part of the enum list, false otherwise.
- */
- _validateEnum: function()
- {
- var _this = this;
-
- if (this.schema["enum"])
- {
- var val = this.data;
-
- if (!this.isRequired() && Alpaca.isValEmpty(val))
- {
- return true;
- }
-
- if (this.options.multiple)
- {
- var isValid = true;
-
- if (!val)
- {
- val = [];
- }
-
- if (!Alpaca.isArray(val) && !Alpaca.isObject(val))
- {
- val = [val];
- }
-
- $.each(val, function(i,v) {
-
- if ($.inArray(v, _this.schema["enum"]) <= -1)
- {
- isValid = false;
- return false;
- }
-
- });
-
- return isValid;
- }
- else
- {
- return ($.inArray(val, this.schema["enum"]) > -1);
- }
- }
- else
- {
- return true;
- }
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- _this.refreshValidationState();
- });
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if ($(":selected",this.control).length < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if ($(":selected",this.control).length > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Select Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Select Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multiple": {
- "title": "Mulitple Selection",
- "description": "Allow multiple selection if true.",
- "type": "boolean",
- "default": false
- },
- "size": {
- "title": "Displayed Options",
- "description": "Number of options to be shown.",
- "type": "number"
- },
- "emptySelectFirst": {
- "title": "Empty Select First",
- "description": "If the data is empty, then automatically select the first item in the list.",
- "type": "boolean",
- "default": false
- },
- "multiselect": {
- "title": "Multiselect Plugin Settings",
- "description": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ListField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multiple": {
- "rightLabel": "Allow multiple selection ?",
- "helper": "Allow multiple selection if checked",
- "type": "checkbox"
- },
- "size": {
- "type": "integer"
- },
- "emptySelectFirst": {
- "type": "checkbox",
- "rightLabel": "Empty Select First"
- },
- "multiselect": {
- "type": "object",
- "rightLabel": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("select", Alpaca.Fields.SelectField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.NumberField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.NumberField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "number";
- //this.inputType = "number";
- // TODO: we can't do this because Chrome screws up it's handling of number type
- // and prevents us from validating properly
- // @see http://stackoverflow.com/questions/16420828/jquery-val-refuses-to-return-non-numeric-input-from-a-number-field-under-chrome
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "number";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var val = this._getControlVal(true);
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseFloat(val);
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateNumber();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotANumber"),
- "status": status
- };
-
- status = this._validateDivisibleBy();
- valInfo["stringDivisibleBy"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("stringDivisibleBy"), [this.schema.divisibleBy]),
- "status": status
- };
-
- status = this._validateMaximum();
- valInfo["stringValueTooLarge"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMaximum) {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLargeExclusive"), [this.schema.maximum]);
- } else {
- valInfo["stringValueTooLarge"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooLarge"), [this.schema.maximum]);
- }
- }
-
- status = this._validateMinimum();
- valInfo["stringValueTooSmall"] = {
- "message": "",
- "status": status
- };
- if (!status) {
- if (this.schema.exclusiveMinimum) {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmallExclusive"), [this.schema.minimum]);
- } else {
- valInfo["stringValueTooSmall"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueTooSmall"), [this.schema.minimum]);
- }
- }
-
- status = this._validateMultipleOf();
- valInfo["stringValueNotMultipleOf"] = {
- "message": "",
- "status": status
- };
- if (!status)
- {
- valInfo["stringValueNotMultipleOf"]["message"] = Alpaca.substituteTokens(this.view.getMessage("stringValueNotMultipleOf"), [this.schema.multipleOf]);
- }
-
- // hand back a true/false
- return baseStatus && valInfo["stringNotANumber"]["status"] && valInfo["stringDivisibleBy"]["status"] && valInfo["stringValueTooLarge"]["status"] && valInfo["stringValueTooSmall"]["status"] && valInfo["stringValueNotMultipleOf"]["status"];
- },
-
- /**
- * Validates if it is a float number.
- * @returns {Boolean} true if it is a float number
- */
- _validateNumber: function() {
-
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid number format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.number, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * Validates divisibleBy constraint.
- * @returns {Boolean} true if it passes the divisibleBy constraint.
- */
- _validateDivisibleBy: function() {
- var floatValue = this.getValue();
- if (!Alpaca.isEmpty(this.schema.divisibleBy)) {
-
- // mod
- if (floatValue % this.schema.divisibleBy !== 0)
- {
- return false;
- }
- }
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the maximum constraint.
- */
- _validateMaximum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.maximum)) {
- if (floatValue > this.schema.maximum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMaximum)) {
- if (floatValue == this.schema.maximum && this.schema.exclusiveMaximum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates maximum constraint.
- * @returns {Boolean} true if it passes the minimum constraint.
- */
- _validateMinimum: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.minimum)) {
- if (floatValue < this.schema.minimum) {
- return false;
- }
-
- if (!Alpaca.isEmpty(this.schema.exclusiveMinimum)) {
- if (floatValue == this.schema.minimum && this.schema.exclusiveMinimum) { // jshint ignore:line
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Validates multipleOf constraint.
- * @returns {Boolean} true if it passes the multipleOf constraint.
- */
- _validateMultipleOf: function() {
- var floatValue = this.getValue();
-
- if (!Alpaca.isEmpty(this.schema.multipleOf)) {
- if (floatValue && this.schema.multipleOf !== 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "number";
- },
-
- /* builder_helpers */
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "Property value must be a multiple of the multipleOf schema property such that division by this value yields an interger (mod zero).",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "number"
- },
- "exclusiveMinimum": {
- "title": "Exclusive Minimum",
- "description": "Property value can not equal the number defined by the minimum schema property.",
- "type": "boolean",
- "default": false
- },
- "exclusiveMaximum": {
- "title": "Exclusive Maximum",
- "description": "Property value can not equal the number defined by the maximum schema property.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "multipleOf": {
- "title": "Multiple Of",
- "description": "The value must be a integral multiple of the property",
- "type": "number"
- },
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property",
- "type": "number"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property",
- "type": "number"
- },
- "exclusiveMinimum": {
- "rightLabel": "Exclusive minimum ?",
- "helper": "Field value must be greater than but not equal to this number if checked",
- "type": "checkbox"
- },
- "exclusiveMaximum": {
- "rightLabel": "Exclusive Maximum ?",
- "helper": "Field value must be less than but not equal to this number if checked",
- "type": "checkbox"
- }
- }
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Number Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Field for float numbers.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringValueTooSmall": "The minimum value for this field is {0}",
- "stringValueTooLarge": "The maximum value for this field is {0}",
- "stringValueTooSmallExclusive": "Value of this field must be greater than {0}",
- "stringValueTooLargeExclusive": "Value of this field must be less than {0}",
- "stringDivisibleBy": "The value must be divisible by {0}",
- "stringNotANumber": "This value is not a number.",
- "stringValueNotMultipleOf": "This value is not a multiple of {0}"
- });
- Alpaca.registerFieldClass("number", Alpaca.Fields.NumberField);
- Alpaca.registerDefaultSchemaFieldMapping("number", "number");
-
-})(jQuery);
-
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ArrayField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ArrayField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "array";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = Alpaca.isEmpty(this.view.toolbarStyle) ? "button" : this.view.toolbarStyle;
- }
- if (!this.options.toolbarStyle) {
- this.options.toolbarStyle = "button";
- }
-
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = Alpaca.isEmpty(this.view.actionbarStyle) ? "top" : this.view.actionbarStyle;
- }
- if (!this.options.actionbarStyle) {
- this.options.actionbarStyle = "top";
- }
-
- // determine whether we are using "ruby on rails" compatibility mode
- this.options.rubyrails = false;
- if (this.parent && this.parent.options && this.parent.options.form && this.parent.options.form.attributes)
- {
- if (!Alpaca.isEmpty(this.parent.options.form.attributes.rubyrails))
- {
- this.options.rubyrails = true;
- }
- }
-
- if (!this.options.items)
- {
- this.options.items = {};
- }
-
- var toolbarSticky = true;
-
- if (!Alpaca.isEmpty(this.view.toolbarSticky))
- {
- toolbarSticky = this.view.toolbarSticky;
- }
-
- if (!Alpaca.isEmpty(this.options.toolbarSticky))
- {
- toolbarSticky = this.options.toolbarSticky;
- }
-
- this.options.toolbarSticky = toolbarSticky;
-
- // Enable forceRevalidation option so that any change in children will trigger parent's revalidation.
- if (this.schema.items && this.schema.uniqueItems)
- {
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
- }
-
- if (typeof(this.data) == "undefined")
- {
- this.data = [];
- }
-
- if (this.data == null)
- {
- this.data = [];
- }
-
- if ("" == this.data)
- {
- this.data = [];
- }
-
- if (Alpaca.isString(this.data))
- {
- // assume to be a serialized array or object, convert
- try
- {
- var parsedJSON = Alpaca.parseJSON(this.data);
-
- if (!Alpaca.isArray(parsedJSON) && !Alpaca.isObject(parsedJSON))
- {
- Alpaca.logWarn("ArrayField parsed string data but it was not an array: " + this.data);
- return;
- }
-
- this.data = parsedJSON;
- }
- catch (e)
- {
- // assume just a string value, put into array
- this.data = [this.data];
- }
- }
-
- if (!Alpaca.isArray(this.data) && !Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ArrayField data is not an array: " + JSON.stringify(this.data, null, " "));
- return;
- }
-
- //
- // ACTIONS
- //
- var applyAction = function(actions, key, actionConfig) {
- var action = self.findAction(actions, key);
- if (!action) {
- action = {
- "core": true
- };
- actions.push(action);
- }
- for (var k in actionConfig) {
- action[k] = actionConfig[k];
- }
- };
- var cleanupActions = function(actions, showLabels) {
- var i = 0;
- do {
-
- // assume enabled by default
- if (typeof(actions[i].enabled) === "undefined") {
- actions[i].enabled = true;
- }
-
- // hide label if global disable
- if (!showLabels) {
- delete actions[i].label;
- }
-
- if (!actions[i].enabled) {
- actions.splice(i, 1);
- } else {
- i++;
- }
-
- } while (i < actions.length);
-
- // sort so that core actions appear first
- actions.sort(function(a, b) {
- if (a.core && !b.core) {
- return -1;
- }
- if (!a.core && b.core) {
- return 1;
- }
- return 0;
- });
- };
-
- // set up default actions for the top array toolbar
- self.toolbar = {};
- if (self.options.toolbar)
- {
- for (var k in self.options.toolbar) {
- self.toolbar[k] = self.options.toolbar[k];
- }
- }
- if (typeof(self.toolbar.showLabels) === "undefined") {
- self.toolbar.showLabels = false;
- }
- if (!self.toolbar.actions) {
- self.toolbar.actions = [];
- }
- applyAction(self.toolbar.actions, "add", {
- "label": "Add New Item",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action)
- {
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(0, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
- }
- });
- cleanupActions(self.toolbar.actions, self.toolbar.showLabels);
-
- // determine which actions to add into the per-item actionbar
- self.actionbar = {};
- if (self.options.actionbar)
- {
- for (var k2 in self.options.actionbar) {
- self.actionbar[k2] = self.options.actionbar[k2];
- }
- }
- if (typeof(self.actionbar.showLabels) === "undefined") {
- self.actionbar.showLabels = false;
- }
- if (!self.actionbar.actions) {
- self.actionbar.actions = [];
- }
- applyAction(self.actionbar.actions, "add", {
- "label": "Add",
- "action": "add",
- "iconClass": self.view.getStyle("addIcon"),
- "click": function(key, action, itemIndex) {
-
- self.resolveItemSchemaOptions(function(itemSchema, itemOptions) {
- var itemData = Alpaca.createEmptyDataInstance(itemSchema);
- self.addItem(itemIndex + 1, itemSchema, itemOptions, itemData, function() {
- // all done
- });
- });
-
- }
- });
- applyAction(self.actionbar.actions, "remove", {
- "label": "Remove",
- "action": "remove",
- "iconClass": self.view.getStyle("removeIcon"),
- "click": function(key, action, itemIndex) {
-
- self.removeItem(itemIndex, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "up", {
- "label": "Up",
- "action": "up",
- "iconClass": self.view.getStyle("upIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex - 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- applyAction(self.actionbar.actions, "down", {
- "label": "Down",
- "action": "down",
- "iconClass": self.view.getStyle("downIcon"),
- "click": function(key, action, itemIndex) {
-
- self.moveItem(itemIndex, itemIndex + 1, self.options.animate, function() {
- // all done
- });
-
- }
- });
- cleanupActions(self.actionbar.actions, self.actionbar.showLabels);
-
- var len = this.data.length;
- var data = $.extend(true, {}, this.data);
- data.length = len;
-
- this.data = Array.prototype.slice.call(data);
- },
-
- /**
- * Picks apart the array and set onto child fields.
- * @see Alpaca.ContainerField#setup
- */
- setValue: function(data)
- {
- var self = this;
-
- if (!data || !Alpaca.isArray(data))
- {
- return;
- }
-
- // set fields
- var i = 0;
- do
- {
- if (i < self.children.length)
- {
- var childField = self.children[i];
-
- if (data.length > i)
- {
- childField.setValue(data[i]);
- i++;
- }
- else
- {
- self.removeItem(i);
- }
- }
- }
- while (i < self.children.length);
-
- // if the number of items in the data is greater than the number of existing child elements
- // then we need to add the new fields
- if (i < data.length)
- {
- self.resolveItemSchemaOptions(function(schema, options) {
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for item: " + i);
- }
-
- // waterfall functions
- var funcs = [];
-
- while (i < data.length)
- {
- var f = (function(i, data)
- {
- return function(callback)
- {
- self.addItem(i, schema, options, data[i], function() {
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
- })(i, data[i]);
-
- funcs.push(f);
-
- i++;
- }
-
- Alpaca.series(funcs, function() {
- // nothing
- });
- });
- }
-
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we're empty and we're also not required, then we hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // otherwise, construct an array and had it back
- var o = [];
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
-
- if (typeof(v) !== "undefined")
- {
- o.push(v);
- }
- }
- return o;
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var self = this;
-
- var items = [];
-
- if (self.data)
- {
- // all items within the array have the same schema and options
- // so we only need to load this once
- self.resolveItemSchemaOptions(function(schema, options) {
-
- // waterfall functions
- var funcs = [];
- for (var index = 0; index < self.data.length; index++)
- {
- var value = self.data[index];
-
- var pf = (function(index, value)
- {
- return function(callback)
- {
- self.createItem(index, schema, options, value, function(item) {
-
- items.push(item);
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
-
- });
- };
-
- })(index, value);
-
- funcs.push(pf);
- }
-
- Alpaca.series(funcs, function(err) {
- callback(items);
- });
-
- });
- }
- else
- {
- callback(items);
- }
- },
-
- /**
- * Workhorse method for createItem.
- *
- * @param index
- * @param itemSchema
- * @param itemOptions
- * @param itemData
- * @param postRenderCallback
- * @return {*}
- * @private
- */
- createItem: function(index, itemSchema, itemOptions, itemData, postRenderCallback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render": function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // setup item path
- fieldControl.path = self.path + "[" + index + "]";
- //fieldControl.nameCalculated = true;
- fieldControl.render(null, function() {
-
- // remember the control
- self.refreshValidationState();
- self.updatePathAndName();
-
- // trigger update on the parent array
- self.triggerUpdate();
-
- if (cb)
- {
- cb();
- }
- });
- },
- "postRender": function(control)
- {
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- // PR: https://github.com/gitana/alpaca/pull/124
- if (Alpaca.isFunction(self.options.items.postRender))
- {
- self.options.items.postRender.call(control, insertionPointEl);
- }
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- }
- },
-
- /**
- * Determines the schema and options to utilize for items within this array.
- *
- * @param callback
- */
- resolveItemSchemaOptions: function(callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedItemSchema, resolvedItemOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedItemOptions.readonly = true;
- }
-
- callback(resolvedItemSchema, resolvedItemOptions, circular);
- };
-
- var itemOptions;
- // legacy support for options.fields.item
- if (!itemOptions && _this.options && _this.options.fields && _this.options.fields.item) {
- itemOptions = _this.options.fields.item;
- }
- if (!itemOptions && _this.options && _this.options.items) {
- itemOptions = _this.options.items;
- }
- var itemSchema;
- if (_this.schema && _this.schema.items) {
- itemSchema = _this.schema.items;
- }
-
- // handle $ref
- if (itemSchema && itemSchema["$ref"])
- {
- var referenceId = itemSchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalItemSchema = itemSchema;
- var originalItemOptions = itemOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(itemSchema, itemOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedItemSchema = {};
- if (originalItemSchema) {
- Alpaca.mergeObject(resolvedItemSchema, originalItemSchema);
- }
- if (itemSchema)
- {
- Alpaca.mergeObject(resolvedItemSchema, itemSchema);
- }
- delete resolvedItemSchema.id;
-
- var resolvedItemOptions = {};
- if (originalItemOptions) {
- Alpaca.mergeObject(resolvedItemOptions, originalItemOptions);
- }
- if (itemOptions)
- {
- Alpaca.mergeObject(resolvedItemOptions, itemOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedItemSchema, resolvedItemOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(itemSchema, itemOptions);
- });
- }
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateUniqueItems();
- valInfo["valueNotUnique"] = {
- "message": status ? "" : this.view.getMessage("valueNotUnique"),
- "status": status
- };
-
- status = this._validateMaxItems();
- valInfo["tooManyItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.maxItems]),
- "status": status
- };
-
- status = this._validateMinItems();
- valInfo["notEnoughItems"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("notEnoughItems"), [this.schema.items.minItems]),
- "status": status
- };
-
- return baseStatus && valInfo["valueNotUnique"]["status"] && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"];
- },
-
- /**
- * Validates if the number of items has been reached to maxItems.
- * @returns {Boolean} true if the number of items has been reached to maxItems
- */
- _validateEqualMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() >= this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if the number of items has been reached to minItems.
- * @returns {Boolean} true if number of items has been reached to minItems
- */
- _validateEqualMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() <= this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been less than minItems.
- * @returns {Boolean} true if number of items has been less than minItems
- */
- _validateMinItems: function()
- {
- if (this.schema.items && this.schema.items.minItems)
- {
- if (this.getSize() < this.schema.items.minItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if number of items has been over maxItems.
- * @returns {Boolean} true if number of items has been over maxItems
- */
- _validateMaxItems: function()
- {
- if (this.schema.items && this.schema.items.maxItems)
- {
- if (this.getSize() > this.schema.items.maxItems)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validates if all items are unique.
- * @returns {Boolean} true if all items are unique.
- */
- _validateUniqueItems: function()
- {
- if (this.schema.items && this.schema.uniqueItems)
- {
- var hash = {};
- for (var i = 0, l = this.children.length; i < l; ++i)
- {
- if (!hash.hasOwnProperty(this.children[i]))
- {
- hash[this.children[i]] = true;
- }
- else
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- findAction: function(actionsArray, actionKey)
- {
- var action = null;
-
- $.each(actionsArray, function(i, v) {
- if (v.action == actionKey) // jshint ignore:line
- {
- action = v;
- }
- });
-
- return action;
- },
-
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
-
- });
- },
-
- /*
- afterApplyCreatedItems: function(model, callback)
- {
- var self = this;
-
- // if there are zero children, show the array toolbar
- self.updateToolbars();
-
- callback();
- },
- */
-
- /**
- * Returns number of children.
- */
- getSize: function() {
- return this.children.length;
- },
-
- /**
- * This method gets invoked after items are dynamically added, removed or moved around in the child chain.
- * It adjusts classes on child DOM elements to make sure they're correct.
- */
- updatePathAndName: function()
- {
- var self = this;
-
- var updateChildrenPathAndName = function(parent)
- {
- if (parent.children)
- {
- $.each(parent.children, function(i, v) {
-
- if (parent.prePath && Alpaca.startsWith(v.path,parent.prePath))
- {
- v.prePath = v.path;
- v.path = v.path.replace(parent.prePath,parent.path);
- }
-
- // re-calculate name
- if (parent.preName && Alpaca.startsWith(v.name, parent.preName))
- {
- v.preName = v.name;
- v.name = v.name.replace(parent.preName, parent.name);
- if (v.field)
- {
- $(v.field).attr('name', v.name);
- }
- }
-
- updateChildrenPathAndName(v);
- });
- }
- };
-
- if (this.children && this.children.length > 0)
- {
- $.each(this.children, function(i, v) {
-
- var idx = v.path.lastIndexOf('/');
- var lastSegment = v.path.substring(idx+1);
- if (lastSegment.indexOf("[") < 0 && lastSegment.indexOf("]") < 0)
- {
- lastSegment = lastSegment.substring(lastSegment.indexOf("[") + 1, lastSegment.indexOf("]"));
- }
-
- if (lastSegment !== i)
- {
- v.prePath = v.path;
- v.path = v.path.substring(0, idx) + "/[" + i + "]";
- }
-
- // re-calculate name
- if (v.nameCalculated)
- {
- v.preName = v.name;
-
- if (v.parent && v.parent.name && v.path)
- {
- v.name = v.parent.name + "_" + i;
- }
- else
- {
- if (v.path)
- {
- v.name = v.path.replace(/\//g, "").replace(/\[/g, "_").replace(/\]/g, "");
- }
- }
-
- if (this.parent.options.rubyrails )
- {
- $(v.field).attr('name', v.parent.name);
- }
- else
- {
- $(v.field).attr('name', v.name);
- }
-
- }
-
- if (!v.prePath)
- {
- v.prePath = v.path;
- }
-
- updateChildrenPathAndName(v);
- });
- }
- },
-
- /**
- * Updates the status of array item action toolbar buttons.
- */
- updateToolbars: function()
- {
- var self = this;
-
- // if we're in display mode, we do not do this
- if (this.view.type === "display")
- {
- return;
- }
-
- // if we're in readonly mode, don't do this
- if (this.schema.readonly)
- {
- return;
- }
-
- // fire callbacks to view to remove and create toolbar
- if (self.toolbar)
- {
- self.fireCallback("arrayToolbar", true);
- self.fireCallback("arrayToolbar");
- }
-
- // fire callbacks to view to remove and create an actionbar for each item
- if (self.actionbar)
- {
- self.fireCallback("arrayActionbars", true);
- self.fireCallback("arrayActionbars");
- }
-
- //
- // TOOLBAR
- //
-
- var toolbarEl = $(this.getFieldEl()).find(".alpaca-array-toolbar[data-alpaca-array-toolbar-field-id='" + self.getId() + "']");
- if (this.children.length > 0)
- {
- // hide toolbar
- $(toolbarEl).hide();
- }
- else
- {
- // show toolbar
- $(toolbarEl).show();
-
- // CLICK: array toolbar buttons
- $(toolbarEl).find("[data-alpaca-array-toolbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-toolbar-action");
- var action = self.findAction(self.toolbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action);
- });
- }
- });
- }
-
-
- //
- // ACTIONBAR
- //
-
- // if we're not using the "sticky" toolbar, then show and hide the item action buttons when hovered
- if (!this.options.toolbarSticky)
- {
- // find each item
- var items = this.getFieldEl().find(".alpaca-container-item");
- $(items).each(function(itemIndex) {
-
- // find the actionbar for this item
- // find from containerItemEl
- var actionbarEl = $(self.containerItemEl).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "'][data-alpaca-array-actionbar-item-index='" + itemIndex + "']");
- if (actionbarEl && actionbarEl.length > 0)
- {
- $(this).hover(function() {
- $(actionbarEl).show();
- }, function() {
- $(actionbarEl).hide();
- });
-
- $(actionbarEl).hide();
- }
- });
- }
- else
- {
- // otherwise, always show the actionbars
- $(self.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-field-id='" + self.getId() + "']").show();
- }
-
- // CLICK: actionbar buttons
- var actionbarEls = $(this.getFieldEl()).find(".alpaca-array-actionbar[data-alpaca-array-actionbar-parent-field-id='" + self.getId() + "']");
- $(actionbarEls).each(function() {
-
- var targetIndex = $(this).attr("data-alpaca-array-actionbar-item-index");
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- // bind button click handlers
- $(this).find("[data-alpaca-array-actionbar-action]").each(function() {
-
- var actionKey = $(this).attr("data-alpaca-array-actionbar-action");
- var action = self.findAction(self.actionbar.actions, actionKey);
- if (action)
- {
- $(this).off().click(function(e) {
- e.preventDefault();
- action.click.call(self, actionKey, action, targetIndex);
- });
- }
- });
-
- // if we're at max capacity, disable "add" buttons
- if (self._validateEqualMaxItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='add']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
-
- // if we're at min capacity, disable "remove" buttons
- if (self._validateEqualMinItems())
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).removeClass('alpaca-button-disabled');
- self.fireCallback("enableButton", this);
- });
- }
- else
- {
- $(this).find("[data-alpaca-array-actionbar-action='remove']").each(function(index) {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- }
- });
- // first actionbar has its "move up" button disabled
- $(actionbarEls).first().find("[data-alpaca-array-actionbar-action='up']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
- // last actionbar has its "move down" button disabled
- $(actionbarEls).last().find("[data-alpaca-array-actionbar-action='down']").each(function() {
- $(this).addClass('alpaca-button-disabled');
- self.fireCallback("disableButton", this);
- });
-
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- doResolveItemContainer: function()
- {
- var self = this;
-
- return $(self.container);
- },
-
- doAddItem: function(index, item)
- {
- var self = this;
-
- var addItemContainer = self.doResolveItemContainer();
-
- // insert into dom
- if (index === 0)
- {
- // insert first into container
- $(addItemContainer).append(item.containerItemEl);
- }
- else
- {
- // insert at a specific index
- var existingElement = addItemContainer.children("[data-alpaca-container-item-index='" + (index-1) + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(item.containerItemEl);
- }
- }
-
- self.doAfterAddItem(item);
- },
-
- doAfterAddItem: function(item)
- {
-
- },
-
- /**
- * Adds an item to the array.
- *
- * This gets called from the toolbar when items are added via the user interface. The method can also
- * be called programmatically to insert items on the fly.
- *
- * @param {Integer} index the index where the item should be inserted
- * @param {Object} schema the json schema
- * @param {Object} options the json options
- * @param {Any} data the data for the newly inserted item
- * @param [Function] callback called after the child is added
- */
- addItem: function(index, schema, options, data, callback)
- {
- var self = this;
-
- if (self._validateEqualMaxItems())
- {
- self.createItem(index, schema, options, data, function(item) {
-
- // register the child
- self.registerChild(item, index);
-
- // insert into dom
- self.doAddItem(index, item);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- }
- },
-
- doRemoveItem: function(childIndex)
- {
- var self = this;
-
- var removeItemContainer = self.doResolveItemContainer();
-
- removeItemContainer.children(".alpaca-container-item[data-alpaca-container-item-index='" + childIndex + "']").remove();
- },
-
- /**
- * Removes an item from the array.
- *
- * This gets called automatically from setValue() when the number of items being set is less than the number
- * of field elements.
-
- * @param {Number} childIndex index of the child to be removed
- * @param [Function] callback called after the child is removed
- */
- removeItem: function(childIndex, callback)
- {
- var self = this;
-
- if (this._validateEqualMinItems())
- {
- // unregister the child
- self.unregisterChild(childIndex);
-
- // remove itemContainerEl from DOM
- self.doRemoveItem(childIndex);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- }
- },
-
- /**
- * Dynamically moves a child to a new index in the array.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to be moved to
- * @param {Boolean} animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- if (sourceIndex === targetIndex)
- {
- // nothing to do
- return;
- }
-
- //console.log("Source: " + sourceIndex + ", Target: " + targetIndex);
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- var parentFieldId = self.getId();
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + sourceIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
- var targetContainer = self.getContainerEl().find(".alpaca-container-item[data-alpaca-container-item-index='" + targetIndex + "'][data-alpaca-container-item-parent-field-id='" + parentFieldId + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find(".alpaca-container-item[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // update the array item toolbar state
- self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- var duration = 0;
- if (animate)
- {
- duration = 500;
- }
-
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, duration, function() {
- onComplete();
- });
- },
-
- /**
- * @see Alpaca.ContainerField#getType
- */
- getType: function() {
- return "array";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.ContainerField#getTitle
- */
- getTitle: function() {
- return "Array Field";
- },
-
- /**
- * @see Alpaca.ContainerField#getDescription
- */
- getDescription: function() {
- return "Field for list of items with same data type or structure.";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "items": {
- "title": "Array Items",
- "description": "Schema for array items.",
- "type": "object",
- "properties": {
- "minItems": {
- "title": "Minimum Items",
- "description": "Minimum number of items.",
- "type": "number"
- },
- "maxItems": {
- "title": "Maximum Items",
- "description": "Maximum number of items.",
- "type": "number"
- },
- "uniqueItems": {
- "title": "Items Unique",
- "description": "Item values should be unique if true.",
- "type": "boolean",
- "default": false
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "items": {
- "type": "object",
- "fields": {
- "minItems": {
- "type": "integer"
- },
- "maxItems": {
- "type": "integer"
- },
- "uniqueItems": {
- "type": "checkbox"
- }
- }
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var properties = {
- "properties": {
- "toolbarSticky": {
- "title": "Sticky Toolbar",
- "description": "Array item toolbar will be aways on if true.",
- "type": "boolean",
- "default": false
- },
- "toolbarStyle": {
- "title": "Toolbar Style",
- "description": "The kind of top-level toolbar to render for the array field. Either 'button' or 'link'.",
- "type": "string",
- "default": "button"
- },
- "actionbarStyle": {
- "title": "Actionbar Style",
- "description": "The kind of actionbar to render for each item in the array. Either 'top', 'bottom', 'left', or 'right'.",
- "type": "string",
- "default": "top"
- },
- "toolbar": {
- "type": "object",
- "title": "Toolbar Configuration",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Toolbar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- },
- "actionbar": {
- "type": "object",
- "properties": {
- "showLabels": {
- "type": "boolean",
- "default": false,
- "title": "Whether to show labels next to actions"
- },
- "actions": {
- "type": "array",
- "title": "Actions Bar Actions Configuration",
- "items": {
- "action": {
- "type": "string",
- "title": "Action Key"
- },
- "label": {
- "type": "string",
- "title": "Action Label"
- },
- "iconClass": {
- "type": "string",
- "title": "Action CSS Classes for Icon"
- },
- "click": {
- "type": "function",
- "title": "Action Click Handler"
- },
- "enabled": {
- "type": "boolean",
- "title": "Whether to enable the action",
- "default": true
- }
- }
- }
- }
- }
- }
- };
-
- if (this.children && this.children[0]) {
- Alpaca.merge(properties.properties.items.properties, this.children[0].getSchemaOfSchema());
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "toolbarSticky": {
- "type": "checkbox"
- },
- "items": {
- "type": "object",
- "fields": {
- }
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "notEnoughItems": "The minimum number of items is {0}",
- "tooManyItems": "The maximum number of items is {0}",
- "valueNotUnique": "Values are not unique",
- "notAnArray": "This value is not an Array"
- });
- Alpaca.registerFieldClass("array", Alpaca.Fields.ArrayField);
- Alpaca.registerDefaultSchemaFieldMapping("array", "array");
-
-})(jQuery);
-
-/*jshint -W004 */ // duplicate variables
-/*jshint -W083 */ // inline functions are used safely
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ObjectField = Alpaca.ContainerField.extend(
- /**
- * @lends Alpaca.Fields.ObjectField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "object";
- },
-
- /**
- * @see Alpaca.ContainerField#setup
- */
- setup: function()
- {
- var self = this;
-
- this.base();
-
- var containerItemTemplateType = self.resolveContainerItemTemplateType();
- if (!containerItemTemplateType)
- {
- var x = self.resolveContainerItemTemplateType();
- return Alpaca.throwErrorWithCallback("Unable to find template descriptor for container item: " + self.getFieldType());
- }
-
- this.containerItemTemplateDescriptor = self.view.getTemplateDescriptor("container-" + containerItemTemplateType + "-item", self);
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
-
- if (this.data === "")
- {
- return;
- }
-
- if (!Alpaca.isObject(this.data))
- {
- if (!Alpaca.isString(this.data))
- {
- return;
- }
- else
- {
- try
- {
- this.data = Alpaca.parseJSON(this.data);
- if (!Alpaca.isObject(this.data))
- {
- Alpaca.logWarn("ObjectField parsed data but it was not an object: " + JSON.stringify(this.data));
- return;
- }
- }
- catch (e)
- {
- return;
- }
- }
- }
- },
-
- /**
- * Picks apart the data object and set onto child fields.
- *
- * @see Alpaca.Field#setValue
- */
- setValue: function(data)
- {
- if (!data)
- {
- data = {};
- }
-
- // if not an object by this point, we don't handle it
- if (!Alpaca.isObject(data))
- {
- return;
- }
-
- // sort existing fields by property id
- var existingFieldsByPropertyId = {};
- for (var fieldId in this.childrenById)
- {
- var propertyId = this.childrenById[fieldId].propertyId;
- existingFieldsByPropertyId[propertyId] = this.childrenById[fieldId];
- }
-
- // new data mapped by property id
- var newDataByPropertyId = {};
- for (var k in data)
- {
- if (data.hasOwnProperty(k))
- {
- newDataByPropertyId[k] = data[k];
- }
- }
-
- // walk through new property ids
- // if a field exists, set value onto it and remove from newDataByPropertyId and existingFieldsByPropertyId
- // if a field doesn't exist, let it remain in list
- for (var propertyId in newDataByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- if (field)
- {
- field.setValue(newDataByPropertyId[propertyId]);
-
- delete existingFieldsByPropertyId[propertyId];
- delete newDataByPropertyId[propertyId];
- }
- }
-
- // anything left in existingFieldsByPropertyId describes data that is missing, null or empty
- // we null out those values
- for (var propertyId in existingFieldsByPropertyId)
- {
- var field = existingFieldsByPropertyId[propertyId];
- field.setValue(null);
- }
-
- // anything left in newDataByPropertyId is new stuff that we need to add
- // the object field doesn't support this since it runs against a schema
- // so we drop this off
- },
-
- /**
- * Reconstructs the data object from the child fields.
- *
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back empty object
- if (this.children.length === 0 && !this.isRequired())
- {
- return {};
- }
-
- // otherwise, hand back an object with our child properties in it
- var o = {};
-
- // walk through all of the properties object
- // for each property, we insert it into a JSON object that we'll hand back as the result
-
- // if the property has dependencies, then we evaluate those dependencies first to determine whether the
- // resulting property should be included
-
- for (var i = 0; i < this.children.length; i++)
- {
- // the property key and vlaue
- var propertyId = this.children[i].propertyId;
- var fieldValue = this.children[i].getValue();
-
- if (typeof(fieldValue) !== "undefined")
- {
- if (this.determineAllDependenciesValid(propertyId))
- {
- var assignedValue = null;
-
- if (typeof(fieldValue) === "boolean")
- {
- assignedValue = (fieldValue? true: false);
- }
- else if (Alpaca.isArray(fieldValue) || Alpaca.isObject(fieldValue) || Alpaca.isNumber(fieldValue))
- {
- assignedValue = fieldValue;
- }
- else if (fieldValue)
- {
- assignedValue = fieldValue;
- }
-
- if (assignedValue !== null)
- {
- o[propertyId] = assignedValue;
- }
- }
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- // Generates wizard if requested
- if (self.isTopLevel())
- {
- if (self.view)
- {
- self.wizardConfigs = self.view.getWizard();
- if (typeof(self.wizardConfigs) != "undefined")
- {
- if (!self.wizardConfigs || self.wizardConfigs === true)
- {
- self.wizardConfigs = {};
- }
- }
-
- var layoutTemplateDescriptor = self.view.getLayout().templateDescriptor;
- if (self.wizardConfigs && Alpaca.isObject(self.wizardConfigs))
- {
- if (!layoutTemplateDescriptor || self.wizardConfigs.bindings)
- {
- // run the automatic wizard
- self.autoWizard();
- }
- else
- {
- // manual wizard based on layout
- self.wizard();
- }
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @override
- *
- * Creates sub-items for this object.
- *
- * @param callback
- */
- createItems: function(callback)
- {
- var _this = this;
-
- var items = [];
-
- // we keep a map of all of the properties in our original data object
- // as we render elements out of the schema, we remove from the extraDataProperties map
- // whatever is leftover are the data properties that were NOT rendered because they were not part
- // of the schema
- //
- // this is primarily maintained for debugging purposes, so as to inform the developer of mismatches
- var extraDataProperties = {};
- for (var dataKey in _this.data) {
- extraDataProperties[dataKey] = dataKey;
- }
-
- var properties = _this.data;
- if (_this.schema && _this.schema.properties) {
- properties = _this.schema.properties;
- }
-
- var cf = function()
- {
- // If the schema and the data line up perfectly, then there will be no properties in the data that are
- // not also in the schema, and thus, extraDataProperties will be empty.
- //
- // On the other hand, if there are some properties in data that were not in schema, then they will
- // remain in extraDataProperties and we can inform developers for debugging purposes
- //
- var extraDataKeys = [];
- for (var extraDataKey in extraDataProperties) {
- extraDataKeys.push(extraDataKey);
- }
- if (extraDataKeys.length > 0) {
- Alpaca.logDebug("There were " + extraDataKeys.length + " extra data keys that were not part of the schema " + JSON.stringify(extraDataKeys));
- }
-
- callback(items);
- };
-
- // each property in the object can have a different schema and options so we need to process
- // asynchronously and wait for all to complete
-
- // wrap into waterfall functions
- var propertyFunctions = [];
- for (var propertyId in properties)
- {
- var itemData = null;
- if (_this.data)
- {
- itemData = _this.data[propertyId];
- }
-
- var pf = (function(propertyId, itemData, extraDataProperties)
- {
- return function(callback)
- {
- // only allow this if we have data, otherwise we end up with circular reference
- _this.resolvePropertySchemaOptions(propertyId, function(schema, options, circular) {
-
- // we only allow addition if the resolved schema isn't circularly referenced
- // or the schema is optional
- if (circular)
- {
- return Alpaca.throwErrorWithCallback("Circular reference detected for schema: " + schema, _this.errorCallback);
- }
-
- if (!schema)
- {
- Alpaca.logDebug("Unable to resolve schema for property: " + propertyId);
- }
-
- _this.createItem(propertyId, schema, options, itemData, null, function(addedItemControl) {
-
- items.push(addedItemControl);
-
- // remove from extraDataProperties helper
- delete extraDataProperties[propertyId];
-
- // by the time we get here, we may have constructed a very large child chain of
- // sub-dependencies and so we use nextTick() instead of a straight callback so as to
- // avoid blowing out the stack size
- Alpaca.nextTick(function() {
- callback();
- });
- });
- });
- };
-
- })(propertyId, itemData, extraDataProperties);
-
- propertyFunctions.push(pf);
- }
-
- Alpaca.series(propertyFunctions, function(err) {
- cf();
- });
- },
-
- /**
- * Creates an sub-item for this object.
- *
- * The postRenderCallback method is called upon completion.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} postRenderCallback called once the item has been added
- */
- createItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, postRenderCallback)
- {
- var self = this;
-
- var formEl = $("");
- formEl.alpaca({
- "data" : itemData,
- "options": itemOptions,
- "schema" : itemSchema,
- "view" : this.view.id ? this.view.id : this.view,
- "connector": this.connector,
- "error": function(err)
- {
- self.destroy();
-
- self.errorCallback.call(self, err);
- },
- "notTopLevel":true,
- "render" : function(fieldControl, cb) {
- // render
- fieldControl.parent = self;
- // add the property Id
- fieldControl.propertyId = propertyId;
- // setup item path
- if (self.path !== "/") {
- fieldControl.path = self.path + "/" + propertyId;
- } else {
- fieldControl.path = self.path + propertyId;
- }
- fieldControl.render(null, function() {
- cb();
- });
- },
- "postRender": function(control) {
-
- // alpaca finished
-
- // render the outer container
- var containerItemEl = Alpaca.tmpl(self.containerItemTemplateDescriptor, {
- "id": self.getId(),
- "name": control.name,
- "parentFieldId": self.getId(),
- "actionbarStyle": self.options.actionbarStyle,
- "view": self.view,
- "data": itemData
- });
-
- // find the insertion point
- var insertionPointEl = $(containerItemEl).find("." + Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD);
- if (insertionPointEl.length === 0)
- {
- if ($(containerItemEl).hasClass(Alpaca.MARKER_CLASS_CONTAINER_FIELD_ITEM_FIELD)) {
- insertionPointEl = $(containerItemEl);
- }
- }
- if (insertionPointEl.length === 0)
- {
- self.errorCallback.call(self, {
- "message": "Cannot find insertion point for field: " + self.getId()
- });
- return;
- }
-
- // copy into place
- $(insertionPointEl).before(control.getFieldEl());
- $(insertionPointEl).remove();
-
- control.containerItemEl = containerItemEl;
-
- if (postRenderCallback)
- {
- postRenderCallback(control);
- }
- }
- });
- },
-
- /**
- * Determines the schema and options to utilize for sub-objects within this object.
- *
- * @param propertyId
- * @param callback
- */
- resolvePropertySchemaOptions: function(propertyId, callback)
- {
- var _this = this;
-
- var completionFunction = function(resolvedPropertySchema, resolvedPropertyOptions, circular)
- {
- // special caveat: if we're in read-only mode, the child must also be in read-only mode
- if (_this.options.readonly) {
- resolvedPropertyOptions.readonly = true;
- }
-
- callback(resolvedPropertySchema, resolvedPropertyOptions, circular);
- };
-
- var propertySchema = null;
- if (_this.schema && _this.schema.properties && _this.schema.properties[propertyId]) {
- propertySchema = _this.schema.properties[propertyId];
- }
- var propertyOptions = {};
- if (_this.options && _this.options.fields && _this.options.fields[propertyId]) {
- propertyOptions = _this.options.fields[propertyId];
- }
-
- // handle $ref
- if (propertySchema && propertySchema["$ref"])
- {
- var referenceId = propertySchema["$ref"];
-
- var topField = this;
- var fieldChain = [topField];
- while (topField.parent)
- {
- topField = topField.parent;
- fieldChain.push(topField);
- }
-
- var originalPropertySchema = propertySchema;
- var originalPropertyOptions = propertyOptions;
-
- Alpaca.loadRefSchemaOptions(topField, referenceId, function(propertySchema, propertyOptions) {
-
- // walk the field chain to see if we have any circularity
- var refCount = 0;
- for (var i = 0; i < fieldChain.length; i++)
- {
- if (fieldChain[i].schema && fieldChain[i].schema.id === referenceId)
- {
- refCount++;
- }
- }
-
- var circular = (refCount > 1);
-
- var resolvedPropertySchema = {};
- if (originalPropertySchema) {
- Alpaca.mergeObject(resolvedPropertySchema, originalPropertySchema);
- }
- if (propertySchema)
- {
- Alpaca.mergeObject(resolvedPropertySchema, propertySchema);
- }
- // keep original id
- if (originalPropertySchema && originalPropertySchema.id) {
- resolvedPropertySchema.id = originalPropertySchema.id;
- }
- //delete resolvedPropertySchema.id;
-
- var resolvedPropertyOptions = {};
- if (originalPropertyOptions) {
- Alpaca.mergeObject(resolvedPropertyOptions, originalPropertyOptions);
- }
- if (propertyOptions)
- {
- Alpaca.mergeObject(resolvedPropertyOptions, propertyOptions);
- }
-
- Alpaca.nextTick(function() {
- completionFunction(resolvedPropertySchema, resolvedPropertyOptions, circular);
- });
- });
- }
- else
- {
- Alpaca.nextTick(function() {
- completionFunction(propertySchema, propertyOptions);
- });
- }
- },
-
- applyCreatedItems: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- var f = function(i)
- {
- if (i === model.items.length)
- {
- // done
- callback();
- return;
- }
-
- var item = model.items[i];
-
- var propertyId = item.propertyId;
-
- // HANDLE PROPERTY DEPENDENCIES (IF THE PROPERTY HAS THEM)
-
- // if this property has dependencies, show or hide this added item right away
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- // if this property has dependencies, bind update handlers to dependent fields
- self.bindDependencyFieldUpdateEvent(propertyId);
-
- // if this property has dependencies, trigger those to ensure it is in the right state
- self.refreshDependentFieldStates(propertyId);
-
- f(i+1);
- };
- f(0);
- });
- },
-
- /**
- * @see Alpaca.ContainerField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateMaxProperties();
- valInfo["tooManyProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyProperties"), [this.schema.maxProperties]),
- "status": status
- };
-
- status = this._validateMinProperties();
- valInfo["tooFewProperties"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("tooManyItems"), [this.schema.items.minProperties]),
- "status": status
- };
-
- return baseStatus && valInfo["tooManyProperties"]["status"] && valInfo["tooFewProperties"]["status"];
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMaxProperties: function()
- {
- if (typeof(this.schema["maxProperties"]) == "undefined")
- {
- return true;
- }
-
- var maxProperties = this.schema["maxProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount <= maxProperties;
- },
-
- /**
- * Validate maxProperties schema property.
- *
- * @returns {Boolean} whether maxProperties is satisfied
- */
- _validateMinProperties: function()
- {
- if (typeof(this.schema["minProperties"]) == "undefined")
- {
- return true;
- }
-
- var minProperties = this.schema["minProperties"];
-
- // count the number of properties that we currently have
- var propertyCount = 0;
- for (var k in this.data)
- {
- propertyCount++;
- }
-
- return propertyCount >= minProperties;
- },
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DEPENDENCIES
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Shows or hides a property's field based on how its dependencies evaluate.
- * If a property doesn't have dependencies, this no-ops.
- *
- * @param propertyId
- */
- showOrHidePropertyBasedOnDependencies: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var valid = this.determineAllDependenciesValid(propertyId);
- if (valid)
- {
- item.show();
- item.onDependentReveal();
- }
- else
- {
- item.hide();
- item.onDependentConceal();
- }
-
- item.getFieldEl().trigger("fieldupdate");
- },
-
- /**
- * Determines whether the dependencies for a property pass.
- *
- * @param propertyId
- */
- determineAllDependenciesValid: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so yes, we pass
- return true;
- }
-
- var valid = true;
- if (Alpaca.isString(itemDependencies))
- {
- valid = self.determineSingleDependencyValid(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- valid = valid && self.determineSingleDependencyValid(propertyId, value);
- });
- }
-
- return valid;
- },
-
- /**
- * Binds field updates to any field dependencies.
- *
- * @param propertyId
- */
- bindDependencyFieldUpdateEvent: function(propertyId)
- {
- var self = this;
-
- var item = this.childrenByPropertyId[propertyId];
- if (!item)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = item.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var bindEvent = function(propertyId, dependencyPropertyId)
- {
- // dependencyPropertyId is the identifier for the property that the field "propertyId" is dependent on
-
- var dependentField = Alpaca.resolveField(self, dependencyPropertyId);
- if (dependentField)
- {
- dependentField.getFieldEl().bind("fieldupdate", (function(propertyField, dependencyField, propertyId, dependencyPropertyId) {
-
- return function(event)
- {
- // the property "dependencyPropertyId" changed and affects target property ("propertyId")
-
- // update UI state for target property
- self.showOrHidePropertyBasedOnDependencies(propertyId);
-
- propertyField.getFieldEl().trigger("fieldupdate");
- };
-
- })(item, dependentField, propertyId, dependencyPropertyId));
-
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- bindEvent(propertyId, itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- bindEvent(propertyId, value);
- });
- }
- },
-
- refreshDependentFieldStates: function(propertyId)
- {
- var self = this;
-
- var propertyField = this.childrenByPropertyId[propertyId];
- if (!propertyField)
- {
- return Alpaca.throwErrorWithCallback("Missing property: " + propertyId, self.errorCallback);
- }
-
- var itemDependencies = propertyField.schema.dependencies;
- if (!itemDependencies)
- {
- // no dependencies, so simple return
- return true;
- }
-
- // helper function
- var triggerFieldUpdateForProperty = function(otherPropertyId)
- {
- var dependentField = Alpaca.resolveField(self, otherPropertyId);
- if (dependentField)
- {
- // trigger field update
- dependentField.getFieldEl().trigger("fieldupdate");
- }
- };
-
- if (Alpaca.isString(itemDependencies))
- {
- triggerFieldUpdateForProperty(itemDependencies);
- }
- else if (Alpaca.isArray(itemDependencies))
- {
- $.each(itemDependencies, function(index, value) {
- triggerFieldUpdateForProperty(value);
- });
- }
- },
-
- /**
- * Checks whether a single property's dependency is satisfied or not.
- *
- * In order to be valid, the property's dependency must exist (JSON schema) and optionally must satisfy
- * any dependency options (value matches using an AND). Finally, the dependency field must be showing.
- *
- * @param {Object} propertyId Field property id.
- * @param {Object} dependentOnPropertyId Property id of the dependency field.
- *
- * @returns {Boolean} True if all dependencies have been satisfied and the field needs to be shown,
- * false otherwise.
- */
- determineSingleDependencyValid: function(propertyId, dependentOnPropertyId)
- {
- var self = this;
-
- // checks to see if the referenced "dependent-on" property has a value
- // basic JSON-schema supports this (if it has ANY value, it is considered valid
- // special consideration for boolean false
- var dependentOnField = Alpaca.resolveField(self, dependentOnPropertyId);
- if (!dependentOnField)
- {
- // no dependent-on field found, return false
- return false;
- }
-
- var dependentOnData = dependentOnField.data;
-
- // assume it isn't valid
- var valid = false;
-
- // go one of two directions depending on whether we have conditional dependencies or not
- var conditionalDependencies = this.childrenByPropertyId[propertyId].options.dependencies;
- if (!conditionalDependencies || conditionalDependencies.length === 0)
- {
- //
- // BASIC DEPENENDENCY CHECKING (CORE JSON SCHEMA)
- //
-
- // special case: if the field is a boolean field and we have no conditional dependency checking,
- // then we set valid = false if the field data is a boolean false
- if (dependentOnField.getType() === "boolean" && !this.childrenByPropertyId[propertyId].options.dependencies && !dependentOnData)
- {
- valid = false;
- }
- else
- {
- valid = !Alpaca.isValEmpty(dependentOnField.data);
- }
- }
- else
- {
- //
- // CONDITIONAL DEPENDENCY CHECKING (ALPACA EXTENSION VIA OPTIONS)
- //
-
- // Alpaca extends JSON schema by allowing dependencies to trigger only for specific values on the
- // dependent fields. If options are specified to define this, we walk through and perform an
- // AND operation across any fields
-
- // do some data sanity cleanup
- if (dependentOnField.getType() === "boolean" && !dependentOnData) {
- dependentOnData = false;
- }
-
- var conditionalData = conditionalDependencies[dependentOnPropertyId];
-
- // if the option is a function, then evaluate the function to determine whether to show
- // the function evaluates regardless of whether the schema-based fallback determined we should show
- if (!Alpaca.isEmpty(conditionalData) && Alpaca.isFunction(conditionalData))
- {
- valid = conditionalData.call(this, dependentOnData);
- }
- else
- {
- // assume true
- valid = true;
-
- // the conditional data is an array of values
- if (Alpaca.isArray(conditionalData)) {
-
- // check array value
- //if (conditionalDependencies[dependentOnPropertyId] && $.inArray(dependentOnData, conditionalDependencies[dependentOnPropertyId]) == -1)
- if (!Alpaca.anyEquality(dependentOnData, conditionalData))
- {
- valid = false;
- }
- }
- else
- {
- // check object value
- if (!Alpaca.isEmpty(conditionalData) && !Alpaca.anyEquality(conditionalData, dependentOnData))
- {
- valid = false;
- }
- }
- }
- }
-
- //
- // NESTED HIDDENS DEPENDENCY HIDES (ALPACA EXTENSION)
- //
-
- // final check: only set valid if the dependentOnPropertyId is showing
- if (dependentOnField && dependentOnField.isHidden())
- {
- valid = false;
- }
-
- return valid;
- },
-
- /**
- * Gets child index.
- *
- * @param {Object} propertyId Child field property ID.
- */
- getIndex: function(propertyId)
- {
- if (Alpaca.isEmpty(propertyId)) {
- return -1;
- }
- for (var i = 0; i < this.children.length; i++) {
- var pid = this.children[i].propertyId;
- if (pid == propertyId) { // jshint ignore:line
- return i;
- }
- }
- return -1;
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // DYNAMIC METHODS
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Adds an item to the object.
- *
- * @param {String} propertyId Child field property ID.
- * @param {Object} itemSchema schema
- * @param {Object} fieldOptions Child field options.
- * @param {Any} value Child field value
- * @param {String} insertAfterId Location where the child item will be inserted.
- * @param [Function} callback called once the item has been added
- */
- addItem: function(propertyId, itemSchema, itemOptions, itemData, insertAfterId, callback)
- {
- var self = this;
-
- this.createItem(propertyId, itemSchema, itemOptions, itemData, insertAfterId, function(child) {
-
- var index = null;
- if (insertAfterId && self.childrenById[insertAfterId])
- {
- for (var z = 0; z < self.children.length; z++)
- {
- if (self.children[z].getId() == insertAfterId)
- {
- index = z;
- break;
- }
- }
- }
-
- // register the child
- self.registerChild(child, ((index != null) ? index + 1 : null));
-
- // insert into dom
- if (!index)
- {
- // insert first into container
- $(self.container).append(child.getFieldEl());
- }
- else
- {
- // insert at a specific index
- var existingElement = self.getContainerEl().children("[data-alpaca-container-item-index='" + index + "']");
- if (existingElement && existingElement.length > 0)
- {
- // insert after
- existingElement.after(child.getFieldEl());
- }
- }
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the array item toolbar state
- //self.updateToolbars();
-
- // refresh validation state
- self.refreshValidationState(true, function() {
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
-
- });
- });
- },
-
- /**
- * Removes an item from the object.
- *
- * @param propertyId
- * @param callback
- */
- removeItem: function(propertyId, callback)
- {
- var self = this;
-
- this.children = $.grep(this.children, function(val, index) {
- return (val.getId() != propertyId);
- });
-
- var childField = this.childrenById[propertyId];
-
- delete this.childrenById[propertyId];
- if (childField.propertyId)
- {
- delete this.childrenByPropertyId[childField.propertyId];
- }
-
- childField.destroy();
-
- this.refreshValidationState(true, function() {
-
- // trigger update handler
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- });
- },
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // WIZARD
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Wraps the current object into a wizard container and wires up the navigation and buttons so that
- * wizard elements flip nicely.
- */
- wizard: function()
- {
- var self = this;
-
- // config-driven
- var stepDescriptors = this.wizardConfigs.steps;
- if (!stepDescriptors)
- {
- stepDescriptors = [];
- }
- var wizardTitle = this.wizardConfigs.title;
- var wizardDescription = this.wizardConfigs.description;
- var buttonDescriptors = this.wizardConfigs.buttons;
- if (!buttonDescriptors)
- {
- buttonDescriptors = {};
- }
- if (!buttonDescriptors["previous"])
- {
- buttonDescriptors["previous"] = {}
- }
- if (!buttonDescriptors["previous"].title)
- {
- buttonDescriptors["previous"].title = "Previous";
- }
- if (!buttonDescriptors["previous"].align)
- {
- buttonDescriptors["previous"].align = "left";
- }
- if (!buttonDescriptors["previous"].type)
- {
- buttonDescriptors["previous"].type = "button";
- }
- if (!buttonDescriptors["next"])
- {
- buttonDescriptors["next"] = {}
- }
- if (!buttonDescriptors["next"].title)
- {
- buttonDescriptors["next"].title = "Next";
- }
- if (!buttonDescriptors["next"].align)
- {
- buttonDescriptors["next"].align = "right";
- }
- if (!buttonDescriptors["next"].type)
- {
- buttonDescriptors["next"].type = "button";
- }
-
- if (!this.wizardConfigs.hideSubmitButton)
- {
- if (!buttonDescriptors["submit"]) {
- buttonDescriptors["submit"] = {}
- }
- if (!buttonDescriptors["submit"].title) {
- buttonDescriptors["submit"].title = "Submit";
- }
- if (!buttonDescriptors["submit"].align) {
- buttonDescriptors["submit"].align = "right";
- }
- if (!buttonDescriptors["submit"].type) {
- buttonDescriptors["submit"].type = "button";
- }
- }
-
- for (var buttonKey in buttonDescriptors)
- {
- if (!buttonDescriptors[buttonKey].type)
- {
- buttonDescriptors[buttonKey].type = "button";
- }
- }
- var showSteps = this.wizardConfigs.showSteps;
- if (typeof(showSteps) == "undefined")
- {
- showSteps = true;
- }
- var showProgressBar = this.wizardConfigs.showProgressBar;
- var performValidation = this.wizardConfigs.validation;
- if (typeof(performValidation) == "undefined")
- {
- performValidation = true;
- }
-
- // DOM-driven configuration
- var wizardTitle = $(this.field).attr("data-alpaca-wizard-title");
- var wizardDescription = $(this.field).attr("data-alpaca-wizard-description");
- var _wizardValidation = $(this.field).attr("data-alpaca-wizard-validation");
- if (typeof(_wizardValidation) != "undefined")
- {
- performValidation = _wizardValidation ? true : false;
- }
- var _wizardShowSteps = $(this.field).attr("data-alpaca-wizard-show-steps");
- if (typeof(_wizardShowSteps) != "undefined")
- {
- showSteps = _wizardShowSteps ? true : false;
- }
- var _wizardShowProgressBar = $(this.field).attr("data-alpaca-wizard-show-progress-bar");
- if (typeof(_wizardShowProgressBar) != "undefined")
- {
- showProgressBar = _wizardShowProgressBar ? true : false;
- }
-
- // find all of the steps
- var stepEls = $(this.field).find("[data-alpaca-wizard-role='step']");
-
- // DOM-driven configuration of step descriptors
- if (stepDescriptors.length == 0)
- {
- stepEls.each(function(i) {
-
- var stepDescriptor = {};
-
- var stepTitle = $(this).attr("data-alpaca-wizard-step-title");
- if (typeof(stepTitle) != "undefined")
- {
- stepDescriptor.title = stepTitle;
- }
- if (!stepDescriptor.title)
- {
- stepDescriptor.title = "Step " + i;
- }
-
- var stepDescription = $(this).attr("data-alpaca-wizard-step-description");
- if (typeof(stepDescription) != "undefined")
- {
- stepDescriptor.description = stepDescription;
- }
- if (!stepDescriptor.description)
- {
- stepDescriptor.description = "Step " + i;
- }
-
- stepDescriptors.push(stepDescriptor);
- });
- }
-
- // assume something for progress bar if not specified
- if (typeof(showProgressBar) == "undefined")
- {
- if (stepDescriptors.length > 1)
- {
- showProgressBar = true;
- }
- }
-
-
- // model for use in rendering the wizard
- var model = {};
- model.wizardTitle = wizardTitle;
- model.wizardDescription = wizardDescription;
- model.showSteps = showSteps;
- model.performValidation = performValidation;
- model.steps = stepDescriptors;
- model.buttons = buttonDescriptors;
- model.schema = self.schema;
- model.options = self.options;
- model.data = self.data;
- model.showProgressBar = showProgressBar;
- model.markAllStepsVisited = this.wizardConfigs.markAllStepsVisited;
- model.view = self.view;
-
- // render the actual wizard
- var wizardTemplateDescriptor = self.view.getTemplateDescriptor("wizard", self);
- if (wizardTemplateDescriptor)
- {
- var wizardEl = Alpaca.tmpl(wizardTemplateDescriptor, model);
-
- $(self.field).append(wizardEl);
-
- var wizardNav = $(wizardEl).find(".alpaca-wizard-nav");
- var wizardSteps = $(wizardEl).find(".alpaca-wizard-steps");
- var wizardButtons = $(wizardEl).find(".alpaca-wizard-buttons");
- var wizardProgressBar = $(wizardEl).find(".alpaca-wizard-progress-bar");
-
- // move steps into place
- $(wizardSteps).append(stepEls);
-
- (function(wizardNav, wizardSteps, wizardButtons, model) {
-
- var currentIndex = 0;
-
- var previousButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='previous']");
- var nextButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='next']");
- var submitButtonEl = $(wizardButtons).find("[data-alpaca-wizard-button-key='submit']");
-
- // snap into place a little controller to work the buttons
- // assume the first step
- var refreshSteps = function()
- {
- // NAV
- if (model.showSteps)
- {
- if (!model.visits)
- {
- model.visits = {};
- }
-
- // optionally mark all steps as visited
- if (model.markAllStepsVisited)
- {
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- for (var g = 0; g < stepElements.length; g++)
- {
- model.visits[g] = true;
- }
- }
-
- // mark current step as visited
- model.visits[currentIndex] = true;
-
- var stepElements = $(wizardNav).find("[data-alpaca-wizard-step-index]");
- $(stepElements).removeClass("disabled");
- $(stepElements).removeClass("completed");
- $(stepElements).removeClass("active");
- $(stepElements).removeClass("visited");
- for (var g = 0; g < stepElements.length; g++)
- {
- if (g < currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("completed");
- }
- else if (g === currentIndex)
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("active");
- }
- else
- {
- if (model.visits && model.visits[g])
- {
- // do not mark disabled for this case
- }
- else
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("disabled");
- }
-
- }
-
- if (model.visits && model.visits[g])
- {
- $(wizardNav).find("[data-alpaca-wizard-step-index='" + g + "']").addClass("visited");
- }
- }
- }
-
- // PROGRESS BAR
- if (model.showProgressBar)
- {
- var valueNow = currentIndex + 1;
- var valueMax = model.steps.length + 1;
- var width = parseInt(((valueNow / valueMax) * 100), 10) + "%";
-
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuemax", valueMax);
- $(wizardProgressBar).find(".progress-bar").attr("aria-valuenow", valueNow);
- $(wizardProgressBar).find(".progress-bar").css("width", width);
- }
-
-
- // BUTTONS
-
- // hide everything
- previousButtonEl.hide();
- nextButtonEl.hide();
- submitButtonEl.hide();
-
- // simple case
- if (model.steps.length == 1)
- {
- submitButtonEl.show();
- }
- else if (model.steps.length > 1)
- {
- if (currentIndex > 0)
- {
- previousButtonEl.show();
- }
-
- nextButtonEl.show();
-
- if (currentIndex == 0)
- {
- nextButtonEl.show();
- }
- else if (currentIndex == model.steps.length - 1)
- {
- nextButtonEl.hide();
- submitButtonEl.show();
- }
- }
-
- // hide all steps
- $(wizardSteps).find("[data-alpaca-wizard-role='step']").hide();
- $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]).show();
-
- };
-
- var assertValidation = function(buttonId, callback)
- {
- if (!model.performValidation)
- {
- callback(true);
- return;
- }
-
- // collect all of the fields on the current step
- var fields = [];
-
- var currentStepEl = $($(wizardSteps).find("[data-alpaca-wizard-role='step']")[currentIndex]);
- $(currentStepEl).find(".alpaca-field").each(function() {
- var fieldId = $(this).attr("data-alpaca-field-id");
- if (fieldId)
- {
- var field = self.childrenById[fieldId];
- if (field)
- {
- fields.push(field);
- }
- }
- });
-
- // wrap into validation functions
- var fns = [];
- for (var i = 0; i < fields.length; i++)
- {
- fns.push(function(field) {
- return function(cb)
- {
- field.refreshValidationState(true, function() {
- cb();
- });
- }
- }(fields[i]));
- }
-
- // run all validations
- Alpaca.series(fns, function() {
-
- var valid = true;
- for (var i = 0; i < fields.length; i++)
- {
- valid = valid && fields[i].isValid(true);
- }
-
- // custom validation function?
- var b = model.buttons[buttonId];
- if (b && b.validate)
- {
- b.validate.call(self, function(_valid) {
- valid = valid && _valid;
- callback(valid);
- });
- }
- else
- {
- callback(valid);
- }
- });
- };
-
- $(previousButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex >= 1)
- {
- //assertValidation("previous", function(valid) {
-
- //if (valid)
- //{
- var b = model.buttons["previous"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex--;
-
- refreshSteps();
- //}
- //});
- }
- });
-
- $(nextButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex + 1 <= model.steps.length - 1)
- {
- assertValidation("next", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["next"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- }
-
- currentIndex++;
-
- refreshSteps();
- }
- });
- }
- });
-
- $(submitButtonEl).click(function(e) {
- e.preventDefault();
-
- if (currentIndex === model.steps.length - 1)
- {
- assertValidation("submit", function(valid) {
-
- if (valid)
- {
- var b = model.buttons["submit"];
- if (b)
- {
- if (b.click)
- {
- b.click.call(self, e);
- }
- else
- {
- // are we in a form?
- if (self.form)
- {
- self.form.submit();
- }
- }
- }
- }
- });
- }
- });
-
- // all custom buttons
- $(wizardButtons).find("[data-alpaca-wizard-button-key]").each(function() {
- var key = $(this).attr("data-alpaca-wizard-button-key");
- if (key != "submit" && key != "next" && key != "previous") { // standard buttons have different behavior
- var b = model.buttons[key];
- if (b && b.click) {
- $(this).click(function (b) {
- return function (e) {
- b.click.call(self, e);
- };
- }(b));
- }
- }
- });
-
- $(wizardNav).find("[data-alpaca-wizard-step-index]").click(function(e) {
- e.preventDefault();
-
- var navIndex = $(this).attr("data-alpaca-wizard-step-index");
- if (navIndex)
- {
- navIndex = parseInt(navIndex, 10);
-
- if (navIndex == currentIndex || (model.visits && model.visits[navIndex]))
- {
- // if we're going backwards, then we do not run validation
- if (navIndex < currentIndex)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- else if (navIndex > currentIndex)
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = navIndex;
- refreshSteps();
- }
- });
- }
- else
- {
- // current item should not be clickable
- }
- }
- }
- });
-
- self.on("moveToStep", function(event) {
-
- var index = event.index;
- var skipValidation = event.skipValidation;
-
- if ((typeof(index) !== "undefined") && index <= model.steps.length - 1)
- {
- if (skipValidation)
- {
- currentIndex = index;
- refreshSteps();
- }
- else
- {
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- currentIndex = index;
-
- refreshSteps();
- }
- });
- }
- }
- });
-
- self.on("advanceOrSubmit", function(event) {
-
- assertValidation(null, function(valid) {
-
- if (valid)
- {
- if (currentIndex === model.steps.length - 1)
- {
- $(submitButtonEl).click();
- }
- else
- {
- $(nextButtonEl).click();
- }
- }
- });
- });
-
-
- refreshSteps();
-
- }(wizardNav, wizardSteps, wizardButtons, model));
- }
- },
-
- /**
- * Renders a configuration-based wizard without a layout template.
- */
- autoWizard: function()
- {
- var stepBindings = this.wizardConfigs.bindings;
- if (!stepBindings)
- {
- stepBindings = {};
- }
-
- for (var propertyId in this.childrenByPropertyId)
- {
- if (!stepBindings.hasOwnProperty(propertyId))
- {
- stepBindings[propertyId] = 1;
- }
- }
-
- // should we create steps?
- var createSteps = true;
- if ($(this.field).find("[data-alpaca-wizard-role='step']").length > 0)
- {
- // already there
- createSteps = false;
- }
-
- var step = 1;
- var col = [];
- do
- {
- // collect fields in this step
- col = [];
- for (var propertyId in stepBindings)
- {
- if (stepBindings[propertyId] == step)
- {
- if (this.childrenByPropertyId && this.childrenByPropertyId[propertyId])
- {
- col.push(this.childrenByPropertyId[propertyId].field);
- }
- }
- }
-
- if (col.length > 0)
- {
- var stepEl = null;
- if (createSteps)
- {
- stepEl = $('');
- $(this.field).append(stepEl);
- }
- else
- {
- stepEl = $($(this.field).find("[data-alpaca-wizard-role='step']")[step-1]);
- }
-
- // move elements in
- for (var i = 0; i < col.length; i++)
- {
- $(stepEl).append(col[i]);
- }
-
- step++;
- }
- }
- while (col.length > 0);
-
- // now run the normal wizard
- this.wizard();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "object";
- },
-
- /**
- * Moves a field.
- *
- * @param {Number} sourceIndex the index of the child to be moved
- * @param {Number} targetIndex the index to which the child should be moved
- * @param [Boolean] animate whether to animate the movement
- * @param [Function] callback called after the child is added
- */
- moveItem: function(sourceIndex, targetIndex, animate, callback)
- {
- var self = this;
-
- if (typeof(animate) == "function")
- {
- callback = animate;
- animate = self.options.animate;
- }
-
- if (typeof(animate) == "undefined")
- {
- animate = self.options.animate ? self.options.animate : true;
- }
-
- if (typeof(sourceIndex) === "string")
- {
- sourceIndex = parseInt(sourceIndex, 10);
- }
-
- if (typeof(targetIndex) === "string")
- {
- targetIndex = parseInt(targetIndex, 10);
- }
-
- if (targetIndex < 0)
- {
- targetIndex = 0;
- }
- if (targetIndex >= self.children.length)
- {
- targetIndex = self.children.length - 1;
- }
-
- if (targetIndex === -1)
- {
- // nothing to swap with
- return;
- }
-
- var targetChild = self.children[targetIndex];
- if (!targetChild)
- {
- // target child not found
- return;
- }
-
- // the source and target DOM elements
- var sourceContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + sourceIndex + "']");
- var targetContainer = self.getContainerEl().children("[data-alpaca-container-item-index='" + targetIndex + "']");
-
- // create two temp elements as markers for switch
- var tempSourceMarker = $("");
- sourceContainer.before(tempSourceMarker);
- var tempTargetMarker = $("");
- targetContainer.before(tempTargetMarker);
-
- var onComplete = function()
- {
- // swap order in children
- var tempChildren = [];
- for (var i = 0; i < self.children.length; i++)
- {
- if (i === sourceIndex)
- {
- tempChildren[i] = self.children[targetIndex];
- }
- else if (i === targetIndex)
- {
- tempChildren[i] = self.children[sourceIndex];
- }
- else
- {
- tempChildren[i] = self.children[i];
- }
- }
- self.children = tempChildren;
-
- // swap order in DOM
- tempSourceMarker.replaceWith(targetContainer);
- tempTargetMarker.replaceWith(sourceContainer);
-
- // updates child dom marker elements
- self.updateChildDOMElements();
-
- // update the action bar bindings
- $(sourceContainer).find("[data-alpaca-array-actionbar-item-index='" + sourceIndex + "']").attr("data-alpaca-array-actionbar-item-index", targetIndex);
- $(targetContainer).find("[data-alpaca-array-actionbar-item-index='" + targetIndex + "']").attr("data-alpaca-array-actionbar-item-index", sourceIndex);
-
- // refresh validation state
- self.refreshValidationState();
-
- // trigger update
- self.triggerUpdate();
-
- if (callback)
- {
- callback();
- }
- };
-
- if (animate)
- {
- // swap divs visually
- Alpaca.animatedSwap(sourceContainer, targetContainer, 500, function() {
- onComplete();
- });
- }
- else
- {
- onComplete();
- }
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Object Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Object field for containing other fields";
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var properties = {
- "properties": {
- "properties": {
- "title": "Properties",
- "description": "List of child properties.",
- "type": "object"
- },
- "maxProperties": {
- "type": "number",
- "title": "Maximum Number Properties",
- "description": "The maximum number of properties that this object is allowed to have"
- },
- "minProperties": {
- "type": "number",
- "title": "Minimum Number of Properties",
- "description": "The minimum number of properties that this object is required to have"
- }
- }
- };
-
- var fieldsProperties = properties.properties.properties;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfSchema();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(this.base(), properties);
- },
-
- /**
- * @private
- * @see Alpaca.ContainerField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- var schemaOfOptions = Alpaca.merge(this.base(), {
- "properties": {
- }
- });
-
- var properties = {
- "properties": {
- "fields": {
- "title": "Field Options",
- "description": "List of options for child fields.",
- "type": "object"
- }
- }
- };
-
- var fieldsProperties = properties.properties.fields;
-
- fieldsProperties.properties = {};
-
- if (this.children) {
- for (var i = 0; i < this.children.length; i++) {
- var propertyId = this.children[i].propertyId;
- fieldsProperties.properties[propertyId] = this.children[i].getSchemaOfOptions();
- fieldsProperties.properties[propertyId].title = propertyId + " :: " + fieldsProperties.properties[propertyId].title;
- }
- }
-
- return Alpaca.merge(schemaOfOptions, properties);
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "tooManyProperties": "The maximum number of properties ({0}) has been exceeded.",
- "tooFewProperties": "There are not enough properties ({0} are required)"
- });
-
- Alpaca.registerFieldClass("object", Alpaca.Fields.ObjectField);
- Alpaca.registerDefaultSchemaFieldMapping("object", "object");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AnyField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.AnyField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "any";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value))
- {
- this.control.val("");
- }
- else
- {
- this.control.val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#disable
- */
- disable: function()
- {
- this.control.disabled = true;
- },
-
- /**
- * @see Alpaca.Field#enable
- */
- enable: function()
- {
- this.control.disabled = false;
- },
-
- /**
- * @see Alpaca.Field#focus
- */
- focus: function()
- {
- this.control.focus();
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "any";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Any Field";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Any field.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("any", Alpaca.Fields.AnyField);
- Alpaca.registerDefaultSchemaFieldMapping("any", "any");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.HiddenField = Alpaca.ControlField.extend(
- /**
- * @lends Alpaca.Fields.ControlField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function()
- {
- return "hidden";
- },
-
- /**
- * @see Alpaca.Field#setup
- */
- setup: function()
- {
- this.base();
- },
-
- /**
- * @see Alpaca.Field#getValue
- */
- getValue: function()
- {
- return this._getControlVal(true);
- },
-
- /**
- * @see Alpaca.Field#setValue
- */
- setValue: function(value)
- {
- if (Alpaca.isEmpty(value)) {
- this.getControlEl().val("");
- } else {
- this.getControlEl().val(value);
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Field#getType
- */
- getType: function() {
- return "string";
- },
-
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Field#getTitle
- */
- getTitle: function() {
- return "Hidden";
- },
-
- /**
- * @see Alpaca.Field#getDescription
- */
- getDescription: function() {
- return "Field for a hidden HTML input";
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerFieldClass("hidden", Alpaca.Fields.HiddenField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.AddressField = Alpaca.Fields.ObjectField.extend(
- /**
- * @lends Alpaca.Fields.AddressField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.ObjectField#getFieldType
- */
- getFieldType: function() {
- return "address";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#setup
- */
- setup: function()
- {
- this.base();
-
- if (this.data === undefined) {
- this.data = {
- street: ['', '']
- };
- }
-
- this.schema = {
- "title": "Home Address",
- "type": "object",
- "properties": {
- "street": {
- "title": "Street",
- "type": "array",
- "items": {
- "type": "string",
- "maxLength": 30,
- "minItems": 0,
- "maxItems": 3
- }
- },
- "city": {
- "title": "City",
- "type": "string"
- },
- "state": {
- "title": "State",
- "type": "string",
- "enum": ["AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY"]
- },
- "zip": {
- "title": "Zip Code",
- "type": "string",
- "pattern": /^(\d{5}(-\d{4})?)?$/
- }
- }
- };
- Alpaca.merge(this.options, {
- "fields": {
- "zip": {
- "maskString": "99999",
- "size": 5
- },
- "state": {
- "optionLabels": ["ALABAMA", "ALASKA", "AMERICANSAMOA", "ARIZONA", "ARKANSAS", "CALIFORNIA", "COLORADO", "CONNECTICUT", "DELAWARE", "DISTRICTOFCOLUMBIA", "FEDERATEDSTATESOFMICRONESIA", "FLORIDA", "GEORGIA", "GUAM", "HAWAII", "IDAHO", "ILLINOIS", "INDIANA", "IOWA", "KANSAS", "KENTUCKY", "LOUISIANA", "MAINE", "MARSHALLISLANDS", "MARYLAND", "MASSACHUSETTS", "MICHIGAN", "MINNESOTA", "MISSISSIPPI", "MISSOURI", "MONTANA", "NEBRASKA", "NEVADA", "NEWHAMPSHIRE", "NEWJERSEY", "NEWMEXICO", "NEWYORK", "NORTHCAROLINA", "NORTHDAKOTA", "NORTHERNMARIANAISLANDS", "OHIO", "OKLAHOMA", "OREGON", "PALAU", "PENNSYLVANIA", "PUERTORICO", "RHODEISLAND", "SOUTHCAROLINA", "SOUTHDAKOTA", "TENNESSEE", "TEXAS", "UTAH", "VERMONT", "VIRGINISLANDS", "VIRGINIA", "WASHINGTON", "WESTVIRGINIA", "WISCONSIN", "WYOMING"]
- }
- }
- });
-
- if (Alpaca.isEmpty(this.options.addressValidation))
- {
- this.options.addressValidation = true;
- }
- },
-
- /**
- * @see Alpaca.Field#isContainer
- */
- isContainer: function()
- {
- return false;
- },
-
- /**
- * Returns address in a single line string.
- *
- * @returns {String} Address as a single line string.
- */
- getAddress: function()
- {
- var value = this.getValue();
- if (this.view.type === "view")
- {
- value = this.data;
- }
- var address = "";
- if (value)
- {
- if (value.street)
- {
- $.each(value.street, function(index, value) {
- address += value + " ";
- });
- }
- if (value.city)
- {
- address += value.city + " ";
- }
- if (value.state)
- {
- address += value.state + " ";
- }
- if (value.zip)
- {
- address += value.zip;
- }
- }
-
- return address;
- },
-
- /**
- * @see Alpaca.Field#afterRenderContainer
- */
- afterRenderContainer: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
- var container = self.getContainerEl();
-
- // apply additional css
- $(container).addClass("alpaca-addressfield");
-
- if (self.options.addressValidation && !self.isDisplayOnly())
- {
- $('').appendTo(container);
- var mapButton = $(' ').appendTo(container);
- if (mapButton.button)
- {
- mapButton.button({
- text: true
- });
- }
- mapButton.click(function() {
-
- if (google && google.maps)
- {
- var geocoder = new google.maps.Geocoder();
- var address = self.getAddress();
- if (geocoder)
- {
- geocoder.geocode({
- 'address': address
- }, function(results, status)
- {
- if (status === google.maps.GeocoderStatus.OK)
- {
- var mapCanvasId = self.getId() + "-map-canvas";
- if ($('#' + mapCanvasId).length === 0)
- {
- $("").appendTo(self.getFieldEl());
- }
-
- var map = new google.maps.Map(document.getElementById(self.getId() + "-map-canvas"), {
- "zoom": 10,
- "center": results[0].geometry.location,
- "mapTypeId": google.maps.MapTypeId.ROADMAP
- });
-
- var marker = new google.maps.Marker({
- map: map,
- position: results[0].geometry.location
- });
-
- }
- else
- {
- self.displayMessage("Geocoding failed: " + status);
- }
- });
- }
-
- }
- else
- {
- self.displayMessage("Google Map API is not installed.");
- }
- }).wrap('');
-
- if (self.options.showMapOnLoad)
- {
- mapButton.click();
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getType
- */
- getType: function() {
- return "any";
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.ObjectField#getTitle
- */
- getTitle: function() {
- return "Address";
- },
-
- /**
- * @see Alpaca.Fields.ObjectField#getDescription
- */
- getDescription: function() {
- return "Standard US Address with Street, City, State and Zip. Also comes with support for Google map.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "validateAddress": {
- "title": "Address Validation",
- "description": "Enable address validation if true",
- "type": "boolean",
- "default": true
- },
- "showMapOnLoad": {
- "title": "Whether to show the map when first loaded",
- "type": "boolean"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.ObjectField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "validateAddress": {
- "helper": "Address validation if checked",
- "rightLabel": "Enable Google Map for address validation?",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("address", Alpaca.Fields.AddressField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CKEditorField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.CKEditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "ckeditor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- if (!this.data)
- {
- this.data = "";
- }
-
- this.base();
-
- if (typeof(this.options.ckeditor) == "undefined")
- {
- this.options.ckeditor = {};
- }
- },
-
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // see if we can render CK Editor
- if (!self.isDisplayOnly() && self.control && typeof(CKEDITOR) !== "undefined")
- {
- // use a timeout because CKEditor has some odd timing dependencies
- setTimeout(function() {
-
- self.editor = CKEDITOR.replace($(self.control)[0], self.options.ckeditor);
-
- }, 250);
- }
-
- // if the ckeditor's dom element gets destroyed, make sure we clean up the editor instance
- $(self.control).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.removeAllListeners();
- self.editor.destroy(false);
- self.editor = null;
- }
-
- });
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the plugin instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- }
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- ,
- getTitle: function() {
- return "CK Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Provides an instance of a CK Editor control for use in editing HTML.";
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "ckeditor": {
- "title": "CK Editor options",
- "description": "Use this entry to provide configuration options to the underlying CKEditor plugin.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.ControlField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "ckeditor": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("ckeditor", Alpaca.Fields.CKEditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ColorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ColorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "color";
- this.inputType = "color";
-
- this.base();
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "color";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Color Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A color picker for selecting hexadecimal color values";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("color", Alpaca.Fields.ColorField);
- Alpaca.registerDefaultSchemaFieldMapping("color", "color");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CountryField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.CountryField.prototype
- */
- {
- /**
- * @see Alpaca.Field#getFieldType
- */
- getFieldType: function() {
- return "country";
- },
-
- /**
- * @see Alpaca.Fields.Field#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize))
- {
- this.options.capitalize = false;
- }
-
- this.schema["enum"] = [];
- this.options.optionLabels = [];
-
- var countriesMap = this.view.getMessage("countries");
- if (countriesMap)
- {
- for (var countryKey in countriesMap)
- {
- this.schema["enum"].push(countryKey);
-
- var label = countriesMap[countryKey];
- if (this.options.capitalize)
- {
- label = label.toUpperCase();
- }
-
- this.options.optionLabels.push(label);
- }
- }
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Country Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of countries keyed by their ISO3 code. The names of the countries are read from the I18N bundle for the current locale.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "capitalize": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("country", Alpaca.Fields.CountryField);
- Alpaca.registerDefaultFormatFieldMapping("country", "country");
-
-})(jQuery);
-
-(function($) {
-
- var round = (function() {
- var strategies = {
- up: Math.ceil,
- down: function(input) { return ~~input; },
- nearest: Math.round
- };
- return function(strategy) {
- return strategies[strategy];
- };
- })();
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.CurrencyField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.CurrencyField.prototype
- */
- {
- /**
- * @constructs
- * @augments Alpaca.Fields.TextField
- *
- * @class Currency Control
- *
- * @param {Object} container Field container.
- * @param {Any} data Field data.
- * @param {Object} options Field options.
- * @param {Object} schema Field schema.
- * @param {Object|String} view Field view.
- * @param {Alpaca.Connector} connector Field connector.
- * @param {Function} errorCallback Error callback.
- */
- constructor: function(container, data, options, schema, view, connector, errorCallback) {
- options = options || {};
-
- var pfOptionsSchema = this.getSchemaOfPriceFormatOptions().properties;
- for (var i in pfOptionsSchema) {
- var option = pfOptionsSchema[i];
- if (!(i in options)) {
- options[i] = option["default"] || undefined;
- }
- }
-
- if (typeof(data) !== "undefined")
- {
- data = "" + parseFloat(data).toFixed(options.centsLimit);
- }
-
- this.base(container, data, options, schema, view, connector, errorCallback);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "currency";
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- var field = this.getControlEl();
-
- this.base(model, function() {
-
- $(field).priceFormat(self.options);
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function() {
-
- var field = this.getControlEl();
-
- var val = $(field).is('input') ? field.val() : field.hmtl();
- if (this.options.unmask || this.options.round !== "none") {
- var unmasked = function() {
- var result = '';
- for (var i in val) {
- var cur = val[i];
- if (!isNaN(cur)) {
- result += cur;
- } else if (cur === this.options.centsSeparator) {
- result += '.';
- }
- }
- return parseFloat(result);
- }.bind(this)();
- if (this.options.round !== "none") {
- unmasked = round(this.options.round)(unmasked);
- if (!this.options.unmask) {
- var result = [];
- var unmaskedString = "" + unmasked;
- for (var i = 0, u = 0; i < val.length; i++) {
- if (!isNaN(val[i])) {
- result.push(unmaskedString[u++] || 0);
- } else {
- result.push(val[i]);
- }
- }
- return result.join('');
- }
- }
- return unmasked;
- } else {
- return val;
- }
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Currency Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides an automatically formatted and configurable input for entering currency amounts.";
- },
-
- getSchemaOfPriceFormatOptions: function() {
- return {
- "properties": {
- "allowNegative": {
- "title": "Allow Negative",
- "description": "Determines if negative numbers are allowed.",
- "type": "boolean",
- "default": false
- },
- "centsLimit": {
- "title": "Cents Limit",
- "description": "The limit of fractional digits.",
- "type": "number",
- "default": 2,
- "minimum": 0
- },
- "centsSeparator": {
- "title": "Cents Separator",
- "description": "The separator between whole and fractional amounts.",
- "type": "text",
- "default": "."
- },
- "clearPrefix": {
- "title": "Clear Prefix",
- "description": "Determines if the prefix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "clearSuffix": {
- "title": "Clear Suffix",
- "description": "Determines if the suffix is cleared on blur.",
- "type": "boolean",
- "default": false
- },
- "insertPlusSign": {
- "title": "Plus Sign",
- "description": "Determines if a plus sign should be inserted for positive values.",
- "type": "boolean",
- "default": false
- },
- "limit": {
- "title": "Limit",
- "description": "A limit of the length of the field.",
- "type": "number",
- "default": undefined,
- "minimum": 0
- },
- "prefix": {
- "title": "Prefix",
- "description": "The prefix if any for the field.",
- "type": "text",
- "default": "$"
- },
- "round": {
- "title": "Round",
- "description": "Determines if the field is rounded. (Rounding is done when getValue is called and is not reflected in the UI)",
- "type": "string",
- "enum": [ "up", "down", "nearest", "none" ],
- "default": "none"
- },
- "suffix": {
- "title": "Suffix",
- "description": "The suffix if any for the field.",
- "type": "text",
- "default": ""
- },
- "thousandsSeparator": {
- "title": "Thousands Separator",
- "description": "The separator between thousands.",
- "type": "string",
- "default": ","
- },
- "unmask": {
- "title": "Unmask",
- "description": "If true then the resulting value for this field will be unmasked. That is, the resulting value will be a float instead of a string (with the prefix, suffix, etc. removed).",
- "type": "boolean",
- "default": true
- }
- }
- };
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), this.getSchemaOfPriceFormatOptions());
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "allowNegative": {
- "type": "checkbox"
- },
- "centsLimit": {
- "type": "number"
- },
- "centsSeparator": {
- "type": "text"
- },
- "clearPrefix": {
- "type": "checkbox"
- },
- "clearSuffix": {
- "type": "checkbox"
- },
- "insertPlusSign": {
- "type": "checkbox"
- },
- "limit": {
- "type": "number"
- },
- "prefix": {
- "type": "text"
- },
- "round": {
- "type": "select"
- },
- "suffix": {
- "type": "text"
- },
- "thousandsSeparator": {
- "type": "string"
- },
- "unmask": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("currency", Alpaca.Fields.CurrencyField);
-
-})(jQuery);
-
-(function($) {
-
- // NOTE: this requires bootstrap-datetimepicker.js
- // NOTE: this requires moment.js
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DateField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.DateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "date";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY";
- },
-
- getDefaultExtraFormats: function() {
- return [];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "date";
- //this.inputType = "date";
-
- this.base();
-
- if (!self.options.picker)
- {
- self.options.picker = {};
- }
-
- if (typeof(self.options.picker.useCurrent) === "undefined") {
- self.options.picker.useCurrent = false;
- }
-
- // date format
-
- if (self.options.picker.format) {
- self.options.dateFormat = self.options.picker.format;
- }
- if (!self.options.dateFormat) {
- self.options.dateFormat = self.getDefaultFormat();
- }
- if (!self.options.picker.format) {
- self.options.picker.format = self.options.dateFormat;
- }
-
- // extra formats
- if (!self.options.picker.extraFormats) {
- var extraFormats = self.getDefaultExtraFormats();
- if (extraFormats) {
- self.options.picker.extraFormats = extraFormats;
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#afterRenderControl
- */
- afterRenderControl: function(model, callback) {
-
- var self = this;
-
- this.base(model, function() {
-
- if (self.view.type !== "display")
- {
- if ($.fn.datetimepicker)
- {
- self.getControlEl().datetimepicker(self.options.picker);
-
- self.picker = self.getControlEl().data("DateTimePicker");
- if (self.picker && self.options.dateFormat)
- {
- self.picker.format(self.options.dateFormat);
- }
- if (self.picker)
- {
- self.options.dateFormat = self.picker.format();
- }
- }
- }
-
- callback();
-
- });
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- getDate: function()
- {
- var self = this;
-
- var date = null;
- try
- {
- if (self.picker)
- {
- date = (self.picker.date() ? self.picker.date()._d: null);
- }
- else
- {
- date = new Date(this.getValue());
- }
- }
- catch (e)
- {
- console.error(e);
- }
-
- return date;
- },
-
- /**
- * Returns field value as a JavaScript Date.
- *
- * @returns {Date} Field value.
- */
- date: function()
- {
- return this.getDate();
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- this.refreshValidationState();
- },
-
- isAutoFocusable: function()
- {
- return false;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateDateFormat();
- valInfo["invalidDate"] = {
- "message": status ? "" : Alpaca.substituteTokens(this.view.getMessage("invalidDate"), [this.options.dateFormat]),
- "status": status
- };
-
- return baseStatus && valInfo["invalidDate"]["status"];
- },
-
- /**
- * Validates date format.
- *
- * @returns {Boolean} True if it is a valid date, false otherwise.
- */
- _validateDateFormat: function()
- {
- var self = this;
-
- var isValid = true;
-
- if (self.options.dateFormat)
- {
- var value = self.getValue();
- if (value || self.isRequired())
- {
- // collect all formats
- var dateFormats = [];
- dateFormats.push(self.options.dateFormat);
- if (self.options.picker && self.options.picker.extraFormats)
- {
- for (var i = 0; i < self.options.picker.extraFormats.length; i++)
- {
- dateFormats.push(self.options.picker.extraFormats[i]);
- }
- }
-
- for (var i = 0; i < dateFormats.length; i++)
- {
- isValid = isValid || moment(value, self.options.dateFormat, true).isValid();
- }
- }
- }
-
- return isValid;
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- this.base(value);
-
- if (this.picker)
- {
- if (moment(value, self.options.dateFormat, true).isValid())
- {
- this.picker.date(value);
- }
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- return this.base();
- },
-
- destroy: function()
- {
- this.base();
-
- this.picker = null;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Date Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Date Field";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"date",
- "enum" : ["date"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "dateFormat": {
- "title": "Date Format",
- "description": "Date format (using moment.js format)",
- "type": "string"
- },
- "picker": {
- "title": "DatetimePicker options",
- "description": "Options that are supported by the Bootstrap DateTime Picker.",
- "type": "any"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "dateFormat": {
- "type": "text"
- },
- "picker": {
- "type": "any"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidDate": "Invalid date for format {0}"
- });
- Alpaca.registerFieldClass("date", Alpaca.Fields.DateField);
- Alpaca.registerDefaultFormatFieldMapping("date", "date");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.DatetimeField = Alpaca.Fields.DateField.extend(
- /**
- * @lends Alpaca.Fields.DatetimeField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "datetime";
- },
-
- getDefaultFormat: function() {
- return "MM/DD/YYYY HH:mm:ss";
- },
-
- getDefaultExtraFormats: function() {
- return [
- "MM/DD/YYYY hh:mm:ss a",
- "MM/DD/YYYY HH:mm",
- "MM/DD/YYYY"
- ];
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- var self = this;
-
- // default html5 input type = "datetime";
- //this.inputType = "datetime";
-
- this.base();
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Datetime Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Datetime Field based on Bootstrap DateTime Picker.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("datetime", Alpaca.Fields.DatetimeField);
-
- // "datetime" is legacy (pre v4 schema)
- Alpaca.registerDefaultFormatFieldMapping("datetime", "datetime");
-
- // official v4 uses date-time
- Alpaca.registerDefaultFormatFieldMapping("date-time", "datetime");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EditorField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EditorField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "editor";
- },
-
- setup: function()
- {
- var self = this;
-
- this.base();
-
- if (!self.options.aceTheme)
- {
- self.options.aceTheme = "ace/theme/chrome";
- }
-
- if (!self.options.aceMode)
- {
- self.options.aceMode = "ace/mode/json";
- }
-
- if (typeof(self.options.beautify) == "undefined")
- {
- self.options.beautify = true;
- }
-
- if (self.options.beautify && this.data)
- {
- if (self.options.aceMode === "ace/mode/json")
- {
- if (Alpaca.isObject(this.data))
- {
- // convert to string to format it
- this.data = JSON.stringify(this.data, null, " ");
- }
- else if (Alpaca.isString(this.data))
- {
- // convert to object and then back to string to format it
- this.data = JSON.stringify(JSON.parse(this.data), null, " ");
- }
- }
-
- if (self.options.aceMode === "ace/mode/html")
- {
- if (typeof(html_beautify) !== "undefined")
- {
- this.data = html_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/css")
- {
- if (typeof(css_beautify) !== "undefined")
- {
- this.data = css_beautify(this.data);
- }
- }
-
- if (self.options.aceMode === "ace/mode/javascript")
- {
- if (typeof(js_beautify) !== "undefined")
- {
- this.data = js_beautify(this.data);
- }
- }
- }
-
- if (self.options.aceMode === "ace/mode/json")
- {
- if (!this.data || this.data === "{}")
- {
- this.data = "{\n\t\n}";
- }
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // ACE HEIGHT
- var aceHeight = self.options.aceHeight;
- if (aceHeight)
- {
- $(self.control).css("height", aceHeight);
- }
-
- // ACE WIDTH
- var aceWidth = self.options.aceWidth;
- if (!aceWidth) {
- aceWidth = "100%";
- }
- $(self.control).css("width", aceWidth);
- }
-
- // locate where we will insert the editor
- var el = $(self.control)[0];
-
- // ace must be included ahead of time
- if (!ace && window.ace) {
- ace = window.ace;
- }
-
- if (!ace)
- {
- Alpaca.logError("Editor Field is missing the 'ace' Cloud 9 Editor");
- }
- else
- {
- self.editor = ace.edit(el);
- self.editor.setOptions({
- maxLines: Infinity
- });
-
- self.editor.getSession().setUseWrapMode(true);
-
- // theme
- var aceTheme = self.options.aceTheme;
- self.editor.setTheme(aceTheme);
-
- // mode
- var aceMode = self.options.aceMode;
- self.editor.getSession().setMode(aceMode);
-
- self.editor.renderer.setHScrollBarAlwaysVisible(false);
- //this.editor.renderer.setVScrollBarAlwaysVisible(false); // not implemented
- self.editor.setShowPrintMargin(false);
-
- // set data onto editor
- self.editor.setValue(self.data);
- self.editor.clearSelection();
-
- // clear undo session
- self.editor.getSession().getUndoManager().reset();
-
- // FIT-CONTENT the height of the editor to the contents contained within
- if (self.options.aceFitContentHeight)
- {
- var heightUpdateFunction = function() {
-
- var first = false;
- if (self.editor.renderer.lineHeight === 0)
- {
- first = true;
- self.editor.renderer.lineHeight = 16;
- }
-
- // http://stackoverflow.com/questions/11584061/
- var newHeight = self.editor.getSession().getScreenLength() * self.editor.renderer.lineHeight + self.editor.renderer.scrollBar.getWidth();
-
- $(self.control).height(newHeight.toString() + "px");
-
- // This call is required for the editor to fix all of
- // its inner structure for adapting to a change in size
- self.editor.resize();
-
- if (first)
- {
- window.setTimeout(function() {
- self.editor.clearSelection();
- }, 100);
- }
- };
-
- // Set initial size to match initial content
- heightUpdateFunction();
-
- // Whenever a change happens inside the ACE editor, update
- // the size again
- self.editor.getSession().on('change', heightUpdateFunction);
- }
-
- // READONLY
- if (self.schema.readonly)
- {
- self.editor.setReadOnly(true);
- }
-
- // if the editor's dom element gets destroyed, make sure we clean up the editor instance
- // normally, we expect Alpaca fields to be destroyed by the destroy() method but they may also be
- // cleaned-up via the DOM, thus we check here.
- $(el).bind('destroyed', function() {
-
- if (self.editor)
- {
- self.editor.destroy();
- self.editor = null;
- }
-
- });
- }
-
- callback();
- });
-
- },
-
- /**
- * @see Alpaca.Field#destroy
- */
- destroy: function()
- {
- // destroy the editor instance
- if (this.editor)
- {
- this.editor.destroy();
- this.editor = null;
- }
-
- // call up to base method
- this.base();
- },
-
- /**
- * @return the ACE editor instance
- */
- getEditor: function()
- {
- return this.editor;
- },
-
- /**
- * @see Alpaca.ControlField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var wordCountStatus = this._validateWordCount();
- valInfo["wordLimitExceeded"] = {
- "message": wordCountStatus ? "" : Alpaca.substituteTokens(this.view.getMessage("wordLimitExceeded"), [this.options.wordlimit]),
- "status": wordCountStatus
- };
-
- var editorAnnotationsStatus = this._validateEditorAnnotations();
- valInfo["editorAnnotationsExist"] = {
- "message": editorAnnotationsStatus ? "" : this.view.getMessage("editorAnnotationsExist"),
- "status": editorAnnotationsStatus
- };
-
- return baseStatus && valInfo["wordLimitExceeded"]["status"] && valInfo["editorAnnotationsExist"]["status"];
- },
-
- _validateEditorAnnotations: function()
- {
- if (this.editor)
- {
- var annotations = this.editor.getSession().getAnnotations();
- if (annotations && annotations.length > 0)
- {
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Validate for word limit.
- *
- * @returns {Boolean} True if the number of words is equal to or less than the word limit.
- */
- _validateWordCount: function()
- {
- if (this.options.wordlimit && this.options.wordlimit > -1)
- {
- var val = this.editor.getValue();
-
- if (val)
- {
- var wordcount = val.split(" ").length;
- if (wordcount > this.options.wordlimit)
- {
- return false;
- }
- }
- }
-
- return true;
- },
-
- /**
- * Force editor to resize to ensure it gets drawn correctly.
- * @override
- */
- onDependentReveal: function()
- {
- if (this.editor)
- {
- this.editor.resize();
- }
- },
-
- /**
- *@see Alpaca.Fields.TextField#setValue
- */
- setValue: function(value)
- {
- var self = this;
-
- if (this.editor)
- {
- if (self.schema.type == "object" && Alpaca.isObject(value))
- {
- // format
- value = JSON.stringify(value, null, " ");
- }
-
- this.editor.setValue(value);
- self.editor.clearSelection();
- }
-
- // be sure to call into base method
- this.base(value);
- },
-
- /**
- * @see Alpaca.Fields.TextField#getValue
- */
- getValue: function()
- {
- var value = null;
-
- if (this.editor)
- {
- value = this.editor.getValue();
- }
-
- // if expected type back is "object", we do the conversion
- if (this.schema.type == "object")
- {
- if (!value)
- {
- value = {};
- }
- else
- {
- value = JSON.parse(value);
- }
- }
-
- return value;
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Editor";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "aceTheme": {
- "title": "ACE Editor Theme",
- "description": "Specifies the theme to set onto the editor instance",
- "type": "string",
- "default": "ace/theme/twilight"
- },
- "aceMode": {
- "title": "ACE Editor Mode",
- "description": "Specifies the mode to set onto the editor instance",
- "type": "string",
- "default": "ace/mode/javascript"
- },
- "aceWidth": {
- "title": "ACE Editor Height",
- "description": "Specifies the width of the wrapping div around the editor",
- "type": "string",
- "default": "100%"
- },
- "aceHeight": {
- "title": "ACE Editor Height",
- "description": "Specifies the height of the wrapping div around the editor",
- "type": "string",
- "default": "300px"
- },
- "aceFitContentHeight": {
- "title": "ACE Fit Content Height",
- "description": "Configures the ACE Editor to auto-fit its height to the contents of the editor",
- "type": "boolean",
- "default": false
- },
- "wordlimit": {
- "title": "Word Limit",
- "description": "Limits the number of words allowed in the text area.",
- "type": "number",
- "default": -1
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "aceTheme": {
- "type": "text"
- },
- "aceMode": {
- "type": "text"
- },
- "wordlimit": {
- "type": "integer"
- }
- }
- });
- }
-
- /* end_builder_helpers */
-
- });
-
- Alpaca.registerMessages({
- "wordLimitExceeded": "The maximum word limit of {0} has been exceeded.",
- "editorAnnotationsExist": "The editor has errors in it that must be corrected"
- });
-
- Alpaca.registerFieldClass("editor", Alpaca.Fields.EditorField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.EmailField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.EmailField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "email";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "email";
- this.inputType = "email";
-
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.email;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidEmail");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Email Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Email Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.email;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"email",
- "enum":["email"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidEmail": "Invalid Email address e.g. info@cloudcms.com"
- });
- Alpaca.registerFieldClass("email", Alpaca.Fields.EmailField);
- Alpaca.registerDefaultFormatFieldMapping("email", "email");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.GridField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.GridField.prototype
- */
- {
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "grid";
- },
-
- setup: function()
- {
- this.base();
-
- if (typeof(this.options.grid) == "undefined")
- {
- this.options.grid = {};
- }
- },
-
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- // convert the data array into the grid's expected format
- var gridData = [];
-
- // add in headers
- var headers = [];
- for (var key in self.options.fields)
- {
- var fieldDefinition = self.options.fields[key];
-
- var label = key;
- if (fieldDefinition.label)
- {
- label = fieldDefinition.label;
- }
-
- headers.push(label);
- }
- gridData.push(headers);
-
- for (var i = 0; i < self.data.length; i++)
- {
- var row = [];
- for (var key2 in self.data[i])
- {
- row.push(self.data[i][key2]);
- }
- gridData.push(row);
- }
-
- /*
- // TODO
- var gridData = [
- ["Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
- ["2009", 0, 2941, 4303, 354, 5814],
- ["2010", 5, 2905, 2867, 412, 5284],
- ["2011", 4, 2517, 4822, 552, 6127],
- ["2012", 2, 2422, 5399, 776, 4151]
- ];
- */
-
- var holder = $(self.container).find(".alpaca-container-grid-holder");
-
- var gridConfig = self.options.grid;
- gridConfig.data = gridData;
-
- $(holder).handsontable(gridConfig);
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.ControlField#getType
- */
- getType: function() {
- return "array";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.ControlField#getTitle
- */
- getTitle: function() {
- return "Grid Field";
- },
-
- /**
- * @see Alpaca.ControlField#getDescription
- */
- getDescription: function() {
- return "Renders array items into a grid";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("grid", Alpaca.Fields.GridField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.ImageField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.ImageField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "image";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Image Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Image Field.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("image", Alpaca.Fields.ImageField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IntegerField = Alpaca.Fields.NumberField.extend(
- /**
- * @lends Alpaca.Fields.IntegerField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.NumberField#getFieldType
- */
- getFieldType: function() {
- return "integer";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (typeof(val) == "undefined" || "" == val)
- {
- return val;
- }
-
- return parseInt(val, 10);
- },
-
- /**
- * @see Alpaca.Field#onChange
- */
- onChange: function(e)
- {
- this.base();
-
- if (this.slider)
- {
- this.slider.slider("value", this.getValue());
- }
- },
-
- /**
- * @see Alpaca.Fields.NumberField#postRender
- */
- postRender: function(callback)
- {
- var self = this;
-
- this.base(function() {
-
- if (self.options.slider)
- {
- if (!Alpaca.isEmpty(self.schema.maximum) && !Alpaca.isEmpty(self.schema.minimum))
- {
- if (self.control)
- {
- self.control.after('');
-
- self.slider = $('#slider', self.control.parent()).slider({
- value: self.getValue(),
- min: self.schema.minimum,
- max: self.schema.maximum,
- slide: function(event, ui) {
- self.setValue(ui.value);
- self.refreshValidationState();
- }
- });
- }
- }
- }
-
- callback();
- });
- },
-
- /**
- * @see Alpaca.Fields.NumberField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateInteger();
- valInfo["stringNotANumber"] = {
- "message": status ? "" : this.view.getMessage("stringNotAnInteger"),
- "status": status
- };
-
- return baseStatus;
- },
-
- /**
- * Validates if it is an integer.
- *
- * @returns {Boolean} true if it is an integer
- */
- _validateInteger: function()
- {
- // get value as text
- var textValue = this._getControlVal();
- if (typeof(textValue) === "number")
- {
- textValue = "" + textValue;
- }
-
- // allow empty
- if (Alpaca.isValEmpty(textValue)) {
- return true;
- }
-
- // check if valid integer format
- var validNumber = Alpaca.testRegex(Alpaca.regexps.integer, textValue);
- if (!validNumber)
- {
- return false;
- }
-
- // quick check to see if what they entered was a number
- var floatValue = this.getValue();
- if (isNaN(floatValue)) {
- return false;
- }
-
- return true;
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getType
- */
- getType: function() {
- return "integer";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.NumberField#getTitle
- */
- getTitle: function() {
- return "Integer Field";
- },
-
- /**
- * @see Alpaca.Fields.NumberField#getDescription
- */
- getDescription: function() {
- return "Field for integers.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "minimum": {
- "title": "Minimum",
- "description": "Minimum value of the property.",
- "type": "integer"
- },
- "maximum": {
- "title": "Maximum",
- "description": "Maximum value of the property.",
- "type": "integer"
- },
- "divisibleBy": {
- "title": "Divisible By",
- "description": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "minimum": {
- "helper": "Minimum value of the field.",
- "type": "integer"
- },
- "maximum": {
- "helper": "Maximum value of the field.",
- "type": "integer"
- },
- "divisibleBy": {
- "helper": "Property value must be divisible by this number.",
- "type": "integer"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "slider": {
- "title": "Slider",
- "description": "Generate jQuery UI slider control with the field if true.",
- "type": "boolean",
- "default": false
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.NumberField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "slider": {
- "rightLabel": "Slider control ?",
- "helper": "Generate slider control if selected.",
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAnInteger": "This value is not an integer."
- });
- Alpaca.registerFieldClass("integer", Alpaca.Fields.IntegerField);
- Alpaca.registerDefaultSchemaFieldMapping("integer", "integer");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.IPv4Field = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.IPv4Field.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "ipv4";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.ipv4;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"])
- {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidIPv4");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "IP Address Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "IP Address Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : Alpaca.regexps.ipv4;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "enum": ["ip-address"],
- "default":"ip-address",
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidIPv4": "Invalid IPv4 address, e.g. 192.168.0.1"
- });
- Alpaca.registerFieldClass("ipv4", Alpaca.Fields.IPv4Field);
- Alpaca.registerDefaultFormatFieldMapping("ip-address", "ipv4");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.JSONField = Alpaca.Fields.TextAreaField.extend(
- /**
- * @lends Alpaca.Fields.JSONField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "json";
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- setValue: function(value)
- {
- if (Alpaca.isObject(value) || typeof(value) === "object")
- {
- value = JSON.stringify(value, null, 3);
- }
-
- this.base(value);
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- var val = this.base();
-
- if (val && Alpaca.isString(val))
- {
- val = JSON.parse(val);
- }
-
- return val;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var status = this._validateJSON();
- valInfo["stringNotAJSON"] = {
- "message": status.status ? "" : this.view.getMessage("stringNotAJSON") +" "+ status.message,
- "status": status.status
- };
-
- return baseStatus && valInfo["stringNotAJSON"]["status"] ;
- },
-
- /**
- * Validates if it is a valid JSON object.
- * @returns {Boolean} true if it is a valid JSON object
- */
- _validateJSON: function()
- {
- var textValue = this.control.val();
-
- // allow null
- if (Alpaca.isValEmpty(textValue))
- {
- return {
- "status" : true
- };
- }
-
- // parse the string
- try
- {
- var obj = JSON.parse(textValue);
-
- // format the string as well
- this.setValue(JSON.stringify(obj, null, 3));
- return {
- "status" : true
- };
- }
- catch(e)
- {
- return {
- "status" : false,
- "message" : e.message
- };
- }
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#postRender
- */
- afterRenderControl: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- if (self.control)
- {
- // Some auto-formatting capabilities
- self.control.bind('keypress', function(e) {
-
- var code = e.keyCode || e.wich;
-
- if (code === 34) {
- self.control.insertAtCaret('"');
- }
- if (code === 123) {
- self.control.insertAtCaret('}');
- }
- if (code === 91) {
- self.control.insertAtCaret(']');
- }
- });
-
- self.control.bind('keypress', 'Ctrl+l', function() {
- self.getFieldEl().removeClass("alpaca-field-focused");
-
- // set class from state
- self.refreshValidationState();
- });
-
- self.control.attr('title','Type Ctrl+L to format and validate the JSON string.');
- }
-
- callback();
-
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "JSON Editor";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Editor for JSON objects with basic validation and formatting.";
- }
-
- /* end_builder_helpers */
- });
-
- // Additional Registrations
- Alpaca.registerMessages({
- "stringNotAJSON": "This value is not a valid JSON string."
- });
-
- Alpaca.registerFieldClass("json", Alpaca.Fields.JSONField);
-
- $.fn.insertAtCaret = function (myValue) {
-
- return this.each(function() {
-
- //IE support
- if (document.selection) {
-
- this.focus();
- sel = document.selection.createRange();
- sel.text = myValue;
- this.focus();
-
- } else if (this.selectionStart || this.selectionStart == '0') { // jshint ignore:line
-
- //MOZILLA / NETSCAPE support
- var startPos = this.selectionStart;
- var endPos = this.selectionEnd;
- var scrollTop = this.scrollTop;
- this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
- this.focus();
- this.selectionStart = startPos /*+ myValue.length*/;
- this.selectionEnd = startPos /*+ myValue.length*/;
- this.scrollTop = scrollTop;
-
- } else {
-
- this.value += myValue;
- this.focus();
- }
- });
- };
-
- /*
- * jQuery Hotkeys Plugin
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- *
- * Based upon the plugin by Tzury Bar Yochay:
- * http://github.com/tzuryby/hotkeys
- *
- * Original idea by:
- * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
- */
- jQuery.hotkeys = {
- version: "0.8",
-
- specialKeys: {
- 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
- 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
- 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
- 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
- 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
- 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
- },
-
- shiftNums: {
- "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
- "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
- ".": ">", "/": "?", "\\": "|"
- }
- };
-
- function keyHandler( handleObj ) {
- // Only care when a possible input has been specified
- if ( typeof handleObj.data !== "string" ) {
- return;
- }
-
- var origHandler = handleObj.handler,
- keys = handleObj.data.toLowerCase().split(" ");
-
- handleObj.handler = function( event ) {
- // Don't fire in text-accepting inputs that we didn't directly bind to
- if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
- event.target.type === "text") ) {
- return;
- }
-
- // Keypress represents characters, not special keys
- var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
- character = String.fromCharCode( event.which ).toLowerCase(),
- key, modif = "", possible = {};
-
- // check combinations (alt|ctrl|shift+anything)
- if ( event.altKey && special !== "alt" ) {
- modif += "alt+";
- }
-
- if ( event.ctrlKey && special !== "ctrl" ) {
- modif += "ctrl+";
- }
-
- // TODO: Need to make sure this works consistently across platforms
- if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
- modif += "meta+";
- }
-
- if ( event.shiftKey && special !== "shift" ) {
- modif += "shift+";
- }
-
- if ( special ) {
- possible[ modif + special ] = true;
-
- } else {
- possible[ modif + character ] = true;
- possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
-
- // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
- if ( modif === "shift+" ) {
- possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
- }
- }
-
- for ( var i = 0, l = keys.length; i < l; i++ ) {
- if ( possible[ keys[i] ] ) {
- return origHandler.apply( this, arguments );
- }
- }
- };
- }
-
- jQuery.each([ "keydown", "keyup", "keypress" ], function() {
- jQuery.event.special[ this ] = { add: keyHandler };
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.LowerCaseField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.LowerCaseField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "lowercase";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var lowerValue = val.toLowerCase();
-
- if (lowerValue != this.getValue()) // jshint ignore:line
- {
- this.base(lowerValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Lowercase Text";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text field for lowercase text.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("lowercase", Alpaca.Fields.LowerCaseField);
- Alpaca.registerDefaultFormatFieldMapping("lowercase", "lowercase");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.MapField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.MapField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextAreaField#getFieldType
- */
- getFieldType: function() {
- return "map";
- },
-
- getType: function()
- {
- return "object"
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#setup
- */
- setup: function()
- {
- // special handling - data can come in as an object, we convert to array
- if (this.data && Alpaca.isObject(this.data))
- {
- var newData = [];
-
- $.each(this.data, function(key, value) {
- var newValue = Alpaca.copyOf(value);
- newValue["_key"] = key;
- newData.push(newValue);
- });
-
- this.data = newData;
- }
-
- this.base();
-
- Alpaca.mergeObject(this.options, {
- "forceRevalidation" : true
- });
-
- if (Alpaca.isEmpty(this.data))
- {
- return;
- }
- },
-
- /**
- * @see Alpaca.ContainerField#getValue
- */
- getValue: function()
- {
- // if we don't have any children and we're not required, hand back undefined
- if (this.children.length === 0 && !this.isRequired())
- {
- return;
- }
-
- // special handling, convert back to object
- var o = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
- if (key)
- {
- delete v["_key"];
- o[key] = v;
- }
- }
-
- return o;
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- var isValidMapKeysNotEmpty = this._validateMapKeysNotEmpty();
- valInfo["keyMissing"] = {
- "message": isValidMapKeysNotEmpty ? "" : this.view.getMessage("keyMissing"),
- "status": isValidMapKeysNotEmpty
- };
-
- var isValidMapKeysUnique = this._validateMapKeysUnique();
- valInfo["keyNotUnique"] = {
- "message": isValidMapKeysUnique ? "" : this.view.getMessage("keyNotUnique"),
- "status": isValidMapKeysUnique
- };
-
- return baseStatus && valInfo["keyMissing"]["status"] && valInfo["keyNotUnique"]["status"];
- },
-
- /**
- * Validates that key fields are not empty.
- *
- * @returns {Boolean} true if keys are not empty
- */
- _validateMapKeysNotEmpty: function()
- {
- var isValid = true;
-
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (!key)
- {
- isValid = false;
- break;
- }
- }
-
- return isValid;
- },
-
- /**
- * Validates if key fields are unique.
- *
- * @returns {Boolean} true if keys are unique
- */
- _validateMapKeysUnique: function()
- {
- var isValid = true;
-
- var keys = {};
- for (var i = 0; i < this.children.length; i++)
- {
- var v = this.children[i].getValue();
- var key = v["_key"];
-
- if (keys[key])
- {
- isValid = false;
- }
-
- keys[key] = key;
- }
-
- return isValid;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextAreaField#getTitle
- */
- getTitle: function() {
- return "Map Field";
- },
-
- /**
- * @see Alpaca.Fields.TextAreaField#getDescription
- */
- getDescription: function() {
- return "Field for objects with key/value pairs that share the same schema for values.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("map", Alpaca.Fields.MapField);
-
- // Additional Registrations
- Alpaca.registerMessages({
- "keyNotUnique": "Keys of map field are not unique.",
- "keyMissing": "Map contains an empty key."
- });
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PasswordField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PasswordField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "password";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- this.base();
-
- if (!this.schema.pattern)
- {
- this.schema.pattern = Alpaca.regexps.password;
- }
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function()
- {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPassword");
- }
-
- return baseStatus;
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Password Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Password Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern)? this.schema.pattern : /^[0-9a-zA-Z\x20-\x7E]*$/;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": this.schema.pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"password",
- "enum":["password"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(),{
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPassword": "Invalid Password"
- });
- Alpaca.registerFieldClass("password", Alpaca.Fields.PasswordField);
- Alpaca.registerDefaultFormatFieldMapping("password", "password");
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PersonalNameField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PersonalNameField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "personalname";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setValue
- */
- setValue: function(val)
- {
- var upperValue = "";
-
- for ( var i = 0; i < val.length; i++ )
- {
- if ( i === 0 )
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else if (val.charAt(i-1) === ' ' || val.charAt(i-1) === '-' || val.charAt(i-1) === "'")
- {
- upperValue += val.charAt(i).toUpperCase();
- }
- else
- {
- upperValue += val.charAt(i);
- }
- }
-
- if (upperValue != this.getValue()) // jshint ignore:line
- {
- this.base(upperValue);
- }
- },
-
- /**
- * @see Alpaca.ControlField#onKeyPress
- */
- onKeyPress: function(e)
- {
- this.base(e);
-
- var _this = this;
-
- Alpaca.later(25, this, function() {
- var v = _this.getValue();
- _this.setValue(v);
- });
-
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Personal Name";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Text Field for personal name with captical letter for first letter & after hyphen, space or apostrophe.";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("personalname", Alpaca.Fields.PersonalNameField);
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.PhoneField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.PhoneField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "tel";
- this.inputType = "tel";
-
- this.base();
-
- if (!this.schema.pattern) {
- this.schema.pattern = Alpaca.regexps.phone;
- }
-
- if (Alpaca.isEmpty(this.options.maskString)) {
- this.options.maskString = "(999) 999-9999";
- }
-
- },
-
- /**
- * @see Alpaca.Fields.TextField#postRender
- */
- postRender: function(callback) {
-
- var self = this;
-
- this.base(function() {
-
- callback();
-
- });
- },
-
- /**
- * @see Alpaca.Fields.TextField#handleValidate
- */
- handleValidate: function() {
- var baseStatus = this.base();
-
- var valInfo = this.validation;
-
- if (!valInfo["invalidPattern"]["status"]) {
- valInfo["invalidPattern"]["message"] = this.view.getMessage("invalidPhone");
- }
-
- return baseStatus;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "phone";
- }
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Phone Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Phone Field.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfSchema
- */
- getSchemaOfSchema: function() {
- var pattern = (this.schema && this.schema.pattern) ? this.schema.pattern : Alpaca.regexps.phone;
- return Alpaca.merge(this.base(), {
- "properties": {
- "pattern": {
- "title": "Pattern",
- "description": "Field Pattern in Regular Expression",
- "type": "string",
- "default": pattern,
- "enum":[pattern],
- "readonly": true
- },
- "format": {
- "title": "Format",
- "description": "Property data format",
- "type": "string",
- "default":"phone",
- "enum":["phone"],
- "readonly":true
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForSchema
- */
- getOptionsForSchema: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- }
- }
- });
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
- return Alpaca.merge(this.base(), {
- "properties": {
- "maskString": {
- "title": "Field Mask String",
- "description": "Expression for field mask",
- "type": "string",
- "default": "(999) 999-9999"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerMessages({
- "invalidPhone": "Invalid Phone Number, e.g. (123) 456-9999"
- });
- Alpaca.registerFieldClass("phone", Alpaca.Fields.PhoneField);
- Alpaca.registerDefaultFormatFieldMapping("phone", "phone");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.Fields.SearchField = Alpaca.Fields.TextField.extend(
- /**
- * @lends Alpaca.Fields.SearchField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // default html5 input type = "search";
- this.inputType = "search";
-
- this.base();
-
- this.options.attributes.results = 5;
- },
-
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "search";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getType
- */
- getType: function() {
- return "string";
- },
-
- /* builder_helpers */
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "Search Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "A search box field";
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("search", Alpaca.Fields.SearchField);
- Alpaca.registerDefaultSchemaFieldMapping("search", "search");
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- Alpaca.usHoldings = {};
-
- Alpaca.usHoldings.territories = {
- "American Samoa" : "AS",
- "District Of Columbia" : "DC",
- "Federated States Of Micronesia" : "FM",
- "Guam" : "GU",
- "Marshall Islands" : "MH",
- "Northern Mariana Islands" : "MP",
- "Palau" : "PW",
- "Puerto Rico" : "PR",
- "Virgin Islands" : "VI"
- };
-
- Alpaca.usHoldings.states = {
- "Alabama" : "AL",
- "Alaska" : "AK",
- "Arizona" : "AZ",
- "Arkansas" : "AR",
- "California" : "CA",
- "Colorado" : "CO",
- "Connecticut" : "CT",
- "Delaware" : "DE",
- "Florida" : "FL",
- "Georgia" : "GA",
- "Hawaii" : "HI",
- "Idaho" : "ID",
- "Illinois" : "IL",
- "Indiana" : "IN",
- "Iowa" : "IA",
- "Kansas" : "KS",
- "Kentucky" : "KY",
- "Louisiana" : "LA",
- "Maine" : "ME",
- "Maryland" : "MD",
- "Massachusetts" : "MA",
- "Michigan" : "MI",
- "Minnesota" : "MN",
- "Mississippi" : "MS",
- "Missouri" : "MO",
- "Montana" : "MT",
- "Nebraska" : "NE",
- "Nevada" : "NV",
- "New Hampshire" : "NH",
- "New Jersey" : "NJ",
- "New Mexico" : "NM",
- "New York" : "NY",
- "North Carolina" : "NC",
- "North Dakota" : "ND",
- "Ohio" : "OH",
- "Oklahoma" : "OK",
- "Oregon" : "OR",
- "Pennsylvania" : "PA",
- "Rhode Island" : "RI",
- "South Carolina" : "SC",
- "South Dakota" : "SD",
- "Tennessee" : "TN",
- "Texas" : "TX",
- "Utah" : "UT",
- "Vermont" : "VT",
- "Virginia" : "VA",
- "Washington" : "WA",
- "West Virginia" : "WV",
- "Wisconsin" : "WI",
- "Wyoming" : "WY"
- };
-
- Alpaca.Fields.StateField = Alpaca.Fields.SelectField.extend(
- /**
- * @lends Alpaca.Fields.StateField.prototype
- */
- {
- /**
- * @see Alpaca.Fields.TextField#getFieldType
- */
- getFieldType: function() {
- return "state";
- },
-
- /**
- * @see Alpaca.Fields.TextField#setup
- */
- setup: function()
- {
- // defaults
- if (Alpaca.isUndefined(this.options.capitalize)) {
- this.options.capitalize = false;
- }
- if (Alpaca.isUndefined(this.options.includeStates)) {
- this.options.includeStates = true;
- }
- if (Alpaca.isUndefined(this.options.includeTerritories)) {
- this.options.includeTerritories = true;
- }
- if (Alpaca.isUndefined(this.options.format)) {
- this.options.format = "name";
- }
-
- // validate settings
- if (this.options.format === "name" || this.options.format === "code")
- {
- // valid formats
- }
- else
- {
- Alpaca.logError("The configured state format: " + this.options.format + " is not a legal value [name, code]");
-
- // default to name format
- this.options.format = "name";
- }
-
- // configure
- var holdings = Alpaca.retrieveUSHoldings(
- this.options.includeStates,
- this.options.includeTerritories,
- (this.options.format === "code"),
- this.options.capitalize);
-
- this.schema["enum"] = holdings.keys;
- this.options.optionLabels = holdings.values;
-
- this.base();
- }
-
-
- /* builder_helpers */
- ,
-
- /**
- * @see Alpaca.Fields.TextField#getTitle
- */
- getTitle: function() {
- return "State Field";
- },
-
- /**
- * @see Alpaca.Fields.TextField#getDescription
- */
- getDescription: function() {
- return "Provides a dropdown selector of states and/or territories in the United States, keyed by their two-character code.";
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getSchemaOfOptions
- */
- getSchemaOfOptions: function() {
-
- return Alpaca.merge(this.base(), {
- "properties": {
- "format": {
- "title": "Format",
- "description": "How to represent the state values in the selector",
- "type": "string",
- "default": "name",
- "enum":["name", "code"],
- "readonly": true
- },
- "capitalize": {
- "title": "Capitalize",
- "description": "Whether the values should be capitalized",
- "type": "boolean",
- "default": false,
- "readonly": true
- },
- "includeStates": {
- "title": "Include States",
- "description": "Whether to include the states of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- },
- "includeTerritories": {
- "title": "Include Territories",
- "description": "Whether to include the territories of the United States",
- "type": "boolean",
- "default": true,
- "readonly": true
- }
- }
- });
-
- },
-
- /**
- * @private
- * @see Alpaca.Fields.TextField#getOptionsForOptions
- */
- getOptionsForOptions: function() {
- return Alpaca.merge(this.base(), {
- "fields": {
- "format": {
- "type": "text"
- },
- "capitalize": {
- "type": "checkbox"
- },
- "includeStates": {
- "type": "checkbox"
- },
- "includeTerritories": {
- "type": "checkbox"
- }
- }
- });
- }
-
- /* end_builder_helpers */
- });
-
- Alpaca.registerFieldClass("state", Alpaca.Fields.StateField);
- Alpaca.registerDefaultFormatFieldMapping("state", "state");
-
- /**
- * Helper function to retrieve the holdings of US states and territories.
- *
- * @param {Boolean} includeStates whether to include US states
- * @param {Boolean} includeTerritories whether to include US territories
- * @param {Boolean} codeValue whether to hand back US holding codes (instead of names)
- * @param {Boolean} capitalize whether to capitalize the values handed back
- *
- * @returns {Object} an object containing "keys" and "values", both of which are arrays.
- */
- Alpaca.retrieveUSHoldings = (function()
- {
- return function(includeStates, includeTerritories, codeValue, capitalize) {
- var res = {
- keys: [],
- values: []
- };
- var opts = $.extend(
- {},
- includeStates ? Alpaca.usHoldings.states : {},
- includeTerritories ? Alpaca.usHoldings.territories : {}
- );
- var sorted = Object.keys(opts);
- sorted.sort();
- for (var i in sorted) {
- var state = sorted[i];
- var key = opts[state];
- var value = codeValue ? key : state;
- if (capitalize) {
- value = value.toUpperCase();
- }
- res.keys.push(key);
- res.values.push(value);
- }
- return res;
- };
- })();
-
-})(jQuery);
-
-(function($) {
-
- var Alpaca = $.alpaca;
-
- /**
- * The table field is used for data representations that consist of an array with objects inside of it. The objects
- * must have a uniform structure. The table field renders a standard HTML table using the table. The individual
- * columns are either editable (in edit mode) or simply displayed in read-only mode.
- */
- Alpaca.Fields.TableField = Alpaca.Fields.ArrayField.extend(
- /**
- * @lends Alpaca.Fields.TableField.prototype
- */
- {
- setup: function()
- {
- var self = this;
-
- if (!self.options)
- {
- self.options = {};
- }
-
- if (typeof(self.options.animate) === "undefined")
- {
- self.options.animate = false;
- }
-
- this.base();
-
- if (!this.options.items.type)
- {
- this.options.items.type = "tablerow";
- }
-
- // support for either "datatable" or "datatables"
- if (this.options.datatable) {
- this.options.datatables = this.options.datatable;
- }
-
- // assume empty options for datatables
- if (typeof(this.options.datatables) === "undefined")
- {
- this.options.datatables = {
- "paging": false,
- "lengthChange": false,
- "info": false,
- "searching": false,
- "ordering": true
- };
- }
-
- // assume actions column to be shown
- if (typeof(this.options.showActionsColumn) === "undefined")
- {
- this.options.showActionsColumn = true;
-
- if (this.options.readonly)
- {
- this.options.showActionsColumn = false;
- }
-
- if (this.isDisplayOnly())
- {
- this.options.showActionsColumn = false;
- }
- }
- },
-
- /**
- * @see Alpaca.ControlField#getFieldType
- */
- getFieldType: function() {
- return "table";
- },
-
- /**
- * The table field uses the "array" container convention to render the DOM. As such, nested objects are wrapped
- * in "field" elements that result in slightly incorrect table structures. Part of the reason for this is that
- * browsers are very fussy when it comes to injection of nested TR or TD partials. Here, we generate most
- * things as DIVs and then do some cleanup in this method to make sure that the table is put togehter in the
- * right way.
- *
- * @param model
- * @param callback
- */
- afterRenderContainer: function(model, callback)
- {
- var self = this;
-
- this.base(model, function() {
-
- self.cleanupDomInjections();
-
- // apply styles of underlying "table"
- var table = $(this.container).find("table");
- self.applyStyle("table", table);
-
- // if the DataTables plugin is available, use it
- if (self.options.datatables)
- {
- if ($.fn.DataTable)
- {
- $(this.container).find("table").DataTable(self.options.datatables);
- }
- }
-
- callback();
-
- }.bind(self));
- },
-
- cleanupDomInjections: function()
- {
- /**
- * Takes a DOM element and merges it "up" to the parent element. Data attributes and some classes are
- * copied from DOM element into the parent element. The children of the DOM element are added to the
- * parent and the DOM element is removed.
- *
- * @param mergeElement
- */
- var mergeElementUp = function(mergeElement)
- {
- var mergeElementParent = $(mergeElement).parent();
- var mergeElementChildren = $(mergeElement).children();
-
- // copy merge element classes to parent
- var classNames =$(mergeElement).attr('class').split(/\s+/);
- $.each( classNames, function(index, className){
- if (className === "alpaca-merge-up") {
- // skip
- } else {
- $(mergeElementParent).addClass(className);
- }
- });
-
- // copy attributes to TR
- $.each($(mergeElement)[0].attributes, function() {
- if (this.name && this.name.indexOf("data-") === 0)
- {
- $(mergeElementParent).attr(this.name, this.value);
- }
- });
-
- // replace field with children
- if (mergeElementChildren.length > 0)
- {
- $(mergeElement).replaceWith(mergeElementChildren);
- }
- else
- {
- $(mergeElement).remove();
- }
- };
-
- // find each TR's .alpaca-field and merge up
- this.getFieldEl().find("tr > .alpaca-field").each(function() {
- mergeElementUp(this);
- });
-
- // find each TR's .alpaca-container and merge up
- this.getFieldEl().find("tr > .alpaca-container").each(function() {
- mergeElementUp(this);
- });
-
- // find the action bar and slip a TD around it
- var alpacaArrayActionbar = this.getFieldEl().find("." + Alpaca.MARKER_CLASS_ARRAY_ITEM_ACTIONBAR);
- if (alpacaArrayActionbar.length > 0)
- {
- alpacaArrayActionbar.each(function() {
- var td = $("