';
+ } else {
+ if (isHorizontalStyle(options.formstyle)) {
+ template += '
';
+ return {template: template, closeTag: closeTag};
+ },
+
+ label: function label(scope, fieldInfo, addButtonMarkup, options) {
+ var labelHTML = '';
+ if ((cssFrameworkService.framework() === 'bs3' || (options.formstyle !== 'inline' && fieldInfo.label !== '')) || addButtonMarkup) {
+ labelHTML = '
' + fieldInfo.label;
+ if (addButtonMarkup) {
+ labelHTML += ' ';
+ }
+ labelHTML += ' ';
+ }
+ return labelHTML;
+ },
+
+ glyphClass: glyphClass,
+
+ allInputsVars: function allInputsVars(scope, fieldInfo, options, modelString, idString, nameString) {
+
+ var placeHolder = fieldInfo.placeHolder;
+
+ var common;
+ var compactClass = '';
+ var sizeClassBS3 = '';
+ var sizeClassBS2 = '';
+ var formControl = '';
+
+ if (cssFrameworkService.framework() === 'bs3') {
+ compactClass = (['horizontal', 'vertical', 'inline'].indexOf(options.formstyle) === -1) ? ' input-sm' : '';
+ sizeClassBS3 = 'col-sm-' + inputSizeHelper.sizeAsNumber(fieldInfo.size);
+ formControl = ' form-control';
+ } else {
+ sizeClassBS2 = (fieldInfo.size ? ' input-' + fieldInfo.size : '');
+ }
+
+ if (options.formstyle === 'inline') {
+ placeHolder = placeHolder || fieldInfo.label;
+ }
+ common = 'ng-model="' + modelString + '"' + (idString ? ' id="' + idString + '" name="' + idString + '" ' : ' name="' + nameString + '" ');
+ common += (placeHolder ? ('placeholder="' + placeHolder + '" ') : '');
+ if (fieldInfo.popup) {
+ common += 'title="' + fieldInfo.popup + '" ';
+ }
+ common += addAllService.addAll(scope, 'Field', null, options);
+ return {
+ common: common,
+ sizeClassBS3: sizeClassBS3,
+ sizeClassBS2: sizeClassBS2,
+ compactClass: compactClass,
+ formControl: formControl
+ };
+ },
+
+ inputChrome: function inputChrome(value, fieldInfo, options: fng.IFormOptions, markupVars) {
+ if (cssFrameworkService.framework() === 'bs3' && isHorizontalStyle(options.formstyle) && fieldInfo.type !== 'checkbox') {
+ value = '
' + value + '
';
+ }
+ // Hack to cope with inline help in directives
+ var inlineHelp = (fieldInfo.helpInline || '') + (fieldInfo.helpinline || '');
+ if (inlineHelp.length > 0) {
+ value += '
' + inlineHelp + ' ';
+ }
+ // If we have chosen
+ value += '
';
+ if (fieldInfo.help) {
+ value += '
' + fieldInfo.help + ' ';
+ }
+ return value;
+ },
+
+ generateSimpleInput: function generateSimpleInput(common, fieldInfo, options) {
+ var result = '
';
+ return result;
+ },
+
+ controlDivClasses: function controlDivClasses(options) {
+ var result = [];
+ if (isHorizontalStyle(options.formstyle)) {
+ result.push(cssFrameworkService.framework() === 'bs2' ? 'controls' : 'col-sm-9');
+ }
+ return result;
+ },
+
+ handleInputAndControlDiv: function handleInputAndControlDiv(inputMarkup, controlDivClasses) {
+ if (controlDivClasses.length > 0) {
+ inputMarkup = '
' + inputMarkup + '
';
+ }
+ return inputMarkup;
+ },
+
+ handleArrayInputAndControlDiv: function handleArrayInputAndControlDiv(inputMarkup, controlDivClasses, info, options: fng.IFormOptions) {
+ var result = '
';
+ result += inputMarkup;
+ if (info.type !== 'link') {
+ result += ' ';
+ }
+ result += '
';
+ return result;
+ },
+
+ addTextInputMarkup: function addTextInputMarkup(allInputsVars, fieldInfo, requiredStr) {
+ var result = '';
+ var setClass = allInputsVars.formControl.trim() + allInputsVars.compactClass + allInputsVars.sizeClassBS2 + (fieldInfo.class ? ' ' + fieldInfo.class : '');
+ if (setClass.length !== 0) {
+ result += 'class="' + setClass + '"';
+ }
+ if (fieldInfo.add) {
+ result += ' ' + fieldInfo.add + ' ';
+ }
+ result += requiredStr + (fieldInfo.readonly ? ' readonly' : '') + ' ';
+ return result;
+ }
+ }
+ }
+}
diff --git a/src/client/js/services/input-size-helper.js b/src/client/js/services/input-size-helper.js
new file mode 100644
index 00000000..9fa0e2ca
--- /dev/null
+++ b/src/client/js/services/input-size-helper.js
@@ -0,0 +1,23 @@
+///
+var fng;
+(function (fng) {
+ var services;
+ (function (services) {
+ /*@ngInject*/
+ function inputSizeHelper() {
+ var sizeMapping = [1, 2, 4, 6, 8, 10, 12];
+ var sizeDescriptions = ['mini', 'small', 'medium', 'large', 'xlarge', 'xxlarge', 'block-level'];
+ var defaultSizeOffset = 2; // medium, which was the default for Twitter Bootstrap 2
+ return {
+ sizeMapping: sizeMapping,
+ sizeDescriptions: sizeDescriptions,
+ defaultSizeOffset: defaultSizeOffset,
+ sizeAsNumber: function (fieldSizeAsText) {
+ return sizeMapping[fieldSizeAsText ? sizeDescriptions.indexOf(fieldSizeAsText) : defaultSizeOffset];
+ }
+ };
+ }
+ services.inputSizeHelper = inputSizeHelper;
+ })(services = fng.services || (fng.services = {}));
+})(fng || (fng = {}));
+//# sourceMappingURL=input-size-helper.js.map
\ No newline at end of file
diff --git a/src/client/js/services/input-size-helper.js.map b/src/client/js/services/input-size-helper.js.map
new file mode 100644
index 00000000..8724f22e
--- /dev/null
+++ b/src/client/js/services/input-size-helper.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"input-size-helper.js","sourceRoot":"","sources":["input-size-helper.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,IAAO,GAAG,CAkBT;AAlBD,WAAO,GAAG;IAAC,IAAA,QAAQ,CAkBlB;IAlBU,WAAA,QAAQ;QAEjB,aAAa;QACb;YAEE,IAAI,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,gBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;YAChG,IAAI,iBAAiB,GAAG,CAAC,CAAC,CAAC,wDAAwD;YAEnF,MAAM,CAAC;gBACL,WAAW,EAAE,WAAW;gBACxB,gBAAgB,EAAE,gBAAgB;gBAClC,iBAAiB,EAAE,iBAAiB;gBACpC,YAAY,EAAE,UAAU,eAAe;oBACrC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;gBACtG,CAAC;aACF,CAAC;QACJ,CAAC;QAde,wBAAe,kBAc9B,CAAA;IACH,CAAC,EAlBU,QAAQ,GAAR,YAAQ,KAAR,YAAQ,QAkBlB;AAAD,CAAC,EAlBM,GAAG,KAAH,GAAG,QAkBT"}
\ No newline at end of file
diff --git a/src/client/js/services/input-size-helper.ts b/src/client/js/services/input-size-helper.ts
new file mode 100644
index 00000000..5be1ea29
--- /dev/null
+++ b/src/client/js/services/input-size-helper.ts
@@ -0,0 +1,21 @@
+///
+
+module fng.services {
+
+ /*@ngInject*/
+ export function inputSizeHelper() {
+
+ var sizeMapping = [1, 2, 4, 6, 8, 10, 12];
+ var sizeDescriptions = ['mini', 'small', 'medium', 'large', 'xlarge', 'xxlarge', 'block-level'];
+ var defaultSizeOffset = 2; // medium, which was the default for Twitter Bootstrap 2
+
+ return {
+ sizeMapping: sizeMapping,
+ sizeDescriptions: sizeDescriptions,
+ defaultSizeOffset: defaultSizeOffset,
+ sizeAsNumber: function (fieldSizeAsText) {
+ return sizeMapping[fieldSizeAsText ? sizeDescriptions.indexOf(fieldSizeAsText) : defaultSizeOffset];
+ }
+ };
+ }
+}
diff --git a/src/client/js/services/plugin-helper.js b/src/client/js/services/plugin-helper.js
new file mode 100644
index 00000000..81190a52
--- /dev/null
+++ b/src/client/js/services/plugin-helper.js
@@ -0,0 +1,114 @@
+///
+var fng;
+(function (fng) {
+ var services;
+ (function (services) {
+ /*
+ A helper service to provide a starting off point for directive plugins
+ */
+ /*@ngInject*/
+ function pluginHelper(formMarkupHelper) {
+ return {
+ extractFromAttr: function extractFromAttr(attr, directiveName) {
+ function deserialize(str) {
+ var retVal = str.replace(/"/g, '"');
+ if (retVal === 'true') {
+ retVal = true;
+ }
+ else if (retVal === 'false') {
+ retVal = false;
+ }
+ else if (!isNaN(parseFloat(retVal)) && isFinite(retVal)) {
+ retVal = parseFloat(retVal);
+ }
+ return retVal;
+ }
+ var info = {};
+ var options = { formStyle: attr.formstyle };
+ var directiveOptions = {};
+ var directiveNameLength = directiveName ? directiveName.length : 0;
+ for (var prop in attr) {
+ if (attr.hasOwnProperty(prop)) {
+ if (prop.slice(0, 6) === 'fngFld') {
+ info[prop.slice(6).toLowerCase()] = deserialize(attr[prop]);
+ }
+ else if (prop.slice(0, 6) === 'fngOpt') {
+ options[prop.slice(6).toLowerCase()] = deserialize(attr[prop]);
+ }
+ else if (directiveName && prop.slice(0, directiveNameLength) === directiveName) {
+ directiveOptions[_.kebabCase(prop.slice(directiveNameLength))] = deserialize(attr[prop]);
+ }
+ }
+ }
+ return { info: info, options: options, directiveOptions: directiveOptions };
+ },
+ buildInputMarkup: function buildInputMarkup(scope, model, info, options, addButtons, needsX, generateInputControl) {
+ var fieldChrome = formMarkupHelper.fieldChrome(scope, info, options, ' id="cg_' + info.id + '"');
+ var controlDivClasses = formMarkupHelper.controlDivClasses(options);
+ var elementHtml = fieldChrome.template + formMarkupHelper.label(scope, info, addButtons, options);
+ var modelString, idString, nameString;
+ if (addButtons) {
+ modelString = 'arrayItem' + (needsX ? '.x' : '');
+ idString = info.id + '_{{$index}}';
+ nameString = info.name + '_{{$index}}';
+ }
+ else {
+ modelString = model + '.' + info.name;
+ idString = info.id;
+ nameString = info.name;
+ }
+ if (options.subschema && info.name.indexOf('.') !== -1) {
+ // Schema handling - need to massage the ngModel and the id
+ var modelBase = model + '.';
+ var compoundName = info.name;
+ var root = options.subschemaroot;
+ var lastPart = compoundName.slice(root.length + 1);
+ modelString = modelBase;
+ if (options.index) {
+ modelString += root + '[' + options.index + '].' + lastPart;
+ idString = 'f_' + modelString.slice(modelBase.length).replace(/(\.|\[|\]\.)/g, '-');
+ }
+ else {
+ modelString += root;
+ if (options.subkey) {
+ idString = modelString.slice(modelBase.length).replace(/\./g, '-') + '-subkey' + options.subkeyno + '-' + lastPart;
+ modelString += '[' + '$_arrayOffset_' + root.replace(/\./g, '_') + '_' + options.subkeyno + '].' + lastPart;
+ }
+ else {
+ modelString += '[$index].' + lastPart;
+ idString = null;
+ nameString = compoundName.replace(/\./g, '-');
+ }
+ }
+ }
+ var buildingBlocks = formMarkupHelper.allInputsVars(scope, info, options, modelString, idString, nameString);
+ buildingBlocks.modelString = modelString;
+ elementHtml += formMarkupHelper['handle' + (addButtons ? 'Array' : '') + 'InputAndControlDiv'](formMarkupHelper.inputChrome(generateInputControl(buildingBlocks), info, options, buildingBlocks), controlDivClasses, info, options);
+ elementHtml += fieldChrome.closeTag;
+ return elementHtml;
+ },
+ findIdInSchemaAndFlagNeedX: function findIdInSchemaAndFlagNeedX(scope, id) {
+ // Find the entry in the schema of scope for id and add a needsX property so string arrays are properly handled
+ var foundIt = false;
+ for (var i = 0; i < scope.length; i++) {
+ var element = scope[i];
+ if (element.id === id) {
+ element.needsX = true;
+ foundIt = true;
+ break;
+ }
+ else if (element.schema) {
+ if (findIdInSchemaAndFlagNeedX(element.schema, id)) {
+ foundIt = true;
+ break;
+ }
+ }
+ }
+ return foundIt;
+ }
+ };
+ }
+ services.pluginHelper = pluginHelper;
+ })(services = fng.services || (fng.services = {}));
+})(fng || (fng = {}));
+//# sourceMappingURL=plugin-helper.js.map
\ No newline at end of file
diff --git a/src/client/js/services/plugin-helper.js.map b/src/client/js/services/plugin-helper.js.map
new file mode 100644
index 00000000..65e60b0d
--- /dev/null
+++ b/src/client/js/services/plugin-helper.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"plugin-helper.js","sourceRoot":"","sources":["plugin-helper.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,IAAO,GAAG,CAkHT;AAlHD,WAAO,GAAG;IAAC,IAAA,QAAQ,CAkHlB;IAlHU,WAAA,QAAQ;QACjB;;WAEG;QAEH,aAAa;QACb,sBAA6B,gBAAgB;YAC3C,MAAM,CAAC;gBACL,eAAe,EAAE,yBAAyB,IAAI,EAAE,aAAa;oBAE3D,qBAAqB,GAAG;wBACtB,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;wBACxC,EAAE,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC;4BACtB,MAAM,GAAG,IAAI,CAAC;wBAChB,CAAC;wBAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC;4BAC9B,MAAM,GAAG,KAAK,CAAC;wBACjB,CAAC;wBAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;4BAC1D,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;wBAC9B,CAAC;wBACD,MAAM,CAAC,MAAM,CAAC;oBAChB,CAAC;oBAED,IAAI,IAAI,GAAG,EAAE,CAAC;oBACd,IAAI,OAAO,GAAG,EAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAC,CAAC;oBAC1C,IAAI,gBAAgB,GAAG,EAAE,CAAC;oBAC1B,IAAI,mBAAmB,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;oBACnE,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;wBACtB,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;4BAC9B,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;gCAClC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;4BAC9D,CAAC;4BAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;gCACzC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;4BACjE,CAAC;4BAAC,IAAI,CAAC,EAAE,CAAC,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC;gCACjF,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;4BAC3F,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,MAAM,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAC,CAAC;gBAC5E,CAAC;gBACD,gBAAgB,EAAE,0BAA0B,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,oBAAoB;oBAC/G,IAAI,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;oBACjG,IAAI,iBAAiB,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBACpE,IAAI,WAAW,GAAG,WAAW,CAAC,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;oBAClG,IAAI,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC;oBAEtC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;wBACf,WAAW,GAAG,WAAW,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBACjD,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,aAAa,CAAC;wBACnC,UAAU,GAAG,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;oBACzC,CAAC;oBAAC,IAAI,CAAC,CAAC;wBACN,WAAW,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC;wBACtC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;wBACnB,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;oBACzB,CAAC;oBAED,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;wBACvD,2DAA2D;wBAC3D,IAAI,SAAS,GAAG,KAAK,GAAG,GAAG,CAAC;wBAC5B,IAAI,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC;wBAC7B,IAAI,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC;wBACjC,IAAI,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBACnD,WAAW,GAAG,SAAS,CAAC;wBAExB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;4BAClB,WAAW,IAAI,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;4BAC5D,QAAQ,GAAG,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;wBACtF,CAAC;wBAAC,IAAI,CAAC,CAAC;4BACN,WAAW,IAAI,IAAI,CAAC;4BACpB,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gCACnB,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC;gCACnH,WAAW,IAAI,GAAG,GAAG,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,QAAQ,CAAC;4BAC9G,CAAC;4BAAC,IAAI,CAAC,CAAC;gCACN,WAAW,IAAI,WAAW,GAAG,QAAQ,CAAC;gCACtC,QAAQ,GAAG,IAAI,CAAC;gCAChB,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;4BAChD,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,IAAI,cAAc,GAAQ,gBAAgB,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;oBAClH,cAAc,CAAC,WAAW,GAAG,WAAW,CAAC;oBAEzC,WAAW,IAAI,gBAAgB,CAAC,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,oBAAoB,CAAC,CAC5F,gBAAgB,CAAC,WAAW,CAC1B,oBAAoB,CAAC,cAAc,CAAC,EACpC,IAAI,EACJ,OAAO,EACP,cAAc,CAAC,EACjB,iBAAiB,EACjB,IAAI,EACJ,OAAO,CAAC,CAAC;oBACX,WAAW,IAAI,WAAW,CAAC,QAAQ,CAAC;oBACpC,MAAM,CAAC,WAAW,CAAC;gBACrB,CAAC;gBACD,0BAA0B,EAAE,oCAAoC,KAAK,EAAE,EAAE;oBACvE,+GAA+G;oBAC/G,IAAI,OAAO,GAAG,KAAK,CAAC;oBAEpB,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACtC,IAAI,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;wBACvB,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;4BACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;4BACtB,OAAO,GAAG,IAAI,CAAC;4BACf,KAAK,CAAC;wBACR,CAAC;wBAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;4BAC1B,EAAE,CAAC,CAAC,0BAA0B,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;gCACnD,OAAO,GAAG,IAAI,CAAC;gCACf,KAAK,CAAC;4BACR,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,MAAM,CAAC,OAAO,CAAC;gBACjB,CAAC;aACF,CAAC;QACJ,CAAC;QA3Ge,qBAAY,eA2G3B,CAAA;IACH,CAAC,EAlHU,QAAQ,GAAR,YAAQ,KAAR,YAAQ,QAkHlB;AAAD,CAAC,EAlHM,GAAG,KAAH,GAAG,QAkHT"}
\ No newline at end of file
diff --git a/src/client/js/services/plugin-helper.ts b/src/client/js/services/plugin-helper.ts
new file mode 100644
index 00000000..d3496a3f
--- /dev/null
+++ b/src/client/js/services/plugin-helper.ts
@@ -0,0 +1,117 @@
+///
+
+module fng.services {
+ /*
+ A helper service to provide a starting off point for directive plugins
+ */
+
+ /*@ngInject*/
+ export function pluginHelper(formMarkupHelper) {
+ return {
+ extractFromAttr: function extractFromAttr(attr, directiveName) {
+
+ function deserialize(str) {
+ var retVal = str.replace(/"/g, '"')
+ if (retVal === 'true') {
+ retVal = true;
+ } else if (retVal === 'false') {
+ retVal = false;
+ } else if (!isNaN(parseFloat(retVal)) && isFinite(retVal)) {
+ retVal = parseFloat(retVal);
+ }
+ return retVal;
+ }
+
+ var info = {};
+ var options = {formStyle: attr.formstyle};
+ var directiveOptions = {};
+ var directiveNameLength = directiveName ? directiveName.length : 0;
+ for (var prop in attr) {
+ if (attr.hasOwnProperty(prop)) {
+ if (prop.slice(0, 6) === 'fngFld') {
+ info[prop.slice(6).toLowerCase()] = deserialize(attr[prop]);
+ } else if (prop.slice(0, 6) === 'fngOpt') {
+ options[prop.slice(6).toLowerCase()] = deserialize(attr[prop]);
+ } else if (directiveName && prop.slice(0, directiveNameLength) === directiveName) {
+ directiveOptions[_.kebabCase(prop.slice(directiveNameLength))] = deserialize(attr[prop]);
+ }
+ }
+ }
+ return {info: info, options: options, directiveOptions: directiveOptions};
+ },
+ buildInputMarkup: function buildInputMarkup(scope, model, info, options, addButtons, needsX, generateInputControl) {
+ var fieldChrome = formMarkupHelper.fieldChrome(scope, info, options, ' id="cg_' + info.id + '"');
+ var controlDivClasses = formMarkupHelper.controlDivClasses(options);
+ var elementHtml = fieldChrome.template + formMarkupHelper.label(scope, info, addButtons, options);
+ var modelString, idString, nameString;
+
+ if (addButtons) {
+ modelString = 'arrayItem' + (needsX ? '.x' : '');
+ idString = info.id + '_{{$index}}';
+ nameString = info.name + '_{{$index}}';
+ } else {
+ modelString = model + '.' + info.name;
+ idString = info.id;
+ nameString = info.name;
+ }
+
+ if (options.subschema && info.name.indexOf('.') !== -1) {
+ // Schema handling - need to massage the ngModel and the id
+ var modelBase = model + '.';
+ var compoundName = info.name;
+ var root = options.subschemaroot;
+ var lastPart = compoundName.slice(root.length + 1);
+ modelString = modelBase;
+
+ if (options.index) {
+ modelString += root + '[' + options.index + '].' + lastPart;
+ idString = 'f_' + modelString.slice(modelBase.length).replace(/(\.|\[|\]\.)/g, '-');
+ } else {
+ modelString += root;
+ if (options.subkey) {
+ idString = modelString.slice(modelBase.length).replace(/\./g, '-') + '-subkey' + options.subkeyno + '-' + lastPart;
+ modelString += '[' + '$_arrayOffset_' + root.replace(/\./g, '_') + '_' + options.subkeyno + '].' + lastPart;
+ } else {
+ modelString += '[$index].' + lastPart;
+ idString = null;
+ nameString = compoundName.replace(/\./g, '-');
+ }
+ }
+ }
+ var buildingBlocks: any = formMarkupHelper.allInputsVars(scope, info, options, modelString, idString, nameString);
+ buildingBlocks.modelString = modelString;
+
+ elementHtml += formMarkupHelper['handle' + (addButtons ? 'Array' : '') + 'InputAndControlDiv'](
+ formMarkupHelper.inputChrome(
+ generateInputControl(buildingBlocks),
+ info,
+ options,
+ buildingBlocks),
+ controlDivClasses,
+ info,
+ options);
+ elementHtml += fieldChrome.closeTag;
+ return elementHtml;
+ },
+ findIdInSchemaAndFlagNeedX: function findIdInSchemaAndFlagNeedX(scope, id) {
+ // Find the entry in the schema of scope for id and add a needsX property so string arrays are properly handled
+ var foundIt = false;
+
+ for (var i = 0; i < scope.length; i++) {
+ var element = scope[i];
+ if (element.id === id) {
+ element.needsX = true;
+ foundIt = true;
+ break;
+ } else if (element.schema) {
+ if (findIdInSchemaAndFlagNeedX(element.schema, id)) {
+ foundIt = true;
+ break;
+ }
+ }
+ }
+ return foundIt;
+ }
+ };
+ }
+}
diff --git a/src/client/js/services/record-handler.js b/src/client/js/services/record-handler.js
new file mode 100644
index 00000000..50cf3c9b
--- /dev/null
+++ b/src/client/js/services/record-handler.js
@@ -0,0 +1,902 @@
+///
+var fng;
+(function (fng) {
+ var services;
+ (function (services) {
+ /**
+ * Operations on a whole record
+ *
+ * All methods should be state-less
+ *
+ */
+ /*@ngInject*/
+ function recordHandler($http, $location, $window, $filter, $timeout, routingService, SubmissionsService, SchemasService) {
+ var suffixCleanId = function suffixCleanId(inst, suffix) {
+ return (inst.id || 'f_' + inst.name).replace(/\./g, '_') + suffix;
+ };
+ var walkTree = function (object, fieldname, element) {
+ // Walk through subdocs to find the required key
+ // for instance walkTree(master,'address.street.number',element)
+ // called by getData and setData
+ // element is used when accessing in the context of a input, as the id (like exams-2-grader)
+ // gives us the element of an array (one level down only for now). Leaving element blank returns the whole array
+ var parts = fieldname.split('.'), higherLevels = parts.length - 1, workingRec = object;
+ for (var i = 0; i < higherLevels; i++) {
+ if (!workingRec) {
+ throw new Error("walkTree failed: Object = " + object + ", fieldname = " + fieldname + ", i = " + i);
+ }
+ if (angular.isArray(workingRec)) {
+ workingRec = _.map(workingRec, function (obj) {
+ return obj[parts[i]];
+ });
+ }
+ else {
+ workingRec = workingRec[parts[i]];
+ }
+ if (angular.isArray(workingRec) && typeof element !== 'undefined') {
+ if (element.scope && typeof element.scope === 'function') {
+ // If we come across an array we need to find the correct position, if we have an element
+ workingRec = workingRec[element.scope().$index];
+ }
+ else if (typeof element === 'number') {
+ workingRec = workingRec[element];
+ }
+ else {
+ throw new Error('Unsupported element type in walkTree ' + fieldname);
+ }
+ }
+ if (!workingRec) {
+ break;
+ }
+ }
+ return {
+ lastObject: workingRec,
+ key: workingRec ? parts[higherLevels] : undefined
+ };
+ };
+ var setData = function setData(object, fieldname, element, value) {
+ var leafData = walkTree(object, fieldname, element);
+ if (leafData.lastObject && leafData.key) {
+ if (angular.isArray(leafData.lastObject)) {
+ for (var i = 0; i < leafData.lastObject.length; i++) {
+ leafData.lastObject[i][leafData.key] = value[i];
+ }
+ }
+ else {
+ leafData.lastObject[leafData.key] = value;
+ }
+ }
+ };
+ var getData = function (object, fieldname, element) {
+ var leafData = walkTree(object, fieldname, element);
+ var retVal;
+ if (leafData.lastObject && leafData.key) {
+ if (angular.isArray(leafData.lastObject)) {
+ retVal = _.map(leafData.lastObject, function (obj) {
+ return obj[leafData.key];
+ });
+ }
+ else {
+ retVal = leafData.lastObject[leafData.key];
+ }
+ }
+ return retVal;
+ };
+ var updateRecordWithLookupValues = function (schemaElement, $scope, ctrlState) {
+ // Update the master and the record with the lookup values, master first
+ if (!$scope.topLevelFormName || $scope[$scope.topLevelFormName].$pristine) {
+ updateObject(schemaElement.name, ctrlState.master, function (value) {
+ return convertForeignKeys(schemaElement, value, $scope[suffixCleanId(schemaElement, 'Options')], $scope[suffixCleanId(schemaElement, '_ids')]);
+ });
+ // Then copy the converted keys from master into record
+ var newVal = getData(ctrlState.master, schemaElement.name);
+ if (newVal) {
+ setData($scope.record, schemaElement.name, undefined, newVal);
+ }
+ }
+ };
+ // Split a field name into the next level and all following levels
+ function splitFieldName(aFieldName) {
+ var nesting = aFieldName.split('.'), result = [nesting[0]];
+ if (nesting.length > 1) {
+ result.push(nesting.slice(1).join('.'));
+ }
+ return result;
+ }
+ var getListData = function getListData($scope, record, fieldName, listSchema) {
+ if (listSchema === void 0) { listSchema = null; }
+ var retVal = record;
+ var nests = fieldName.split('.');
+ for (var i = 0; i < nests.length; i++) {
+ if (retVal !== undefined && retVal !== null && nests && nests[i]) {
+ retVal = retVal[nests[i]];
+ }
+ }
+ if (retVal === undefined) {
+ retVal = '';
+ }
+ if (retVal && listSchema) {
+ // Convert list fields as per instructions in params (ideally should be the same as what is found in data_form getListFields
+ var schemaElm = _.find(listSchema, function (elm) { return (elm['name'] === fieldName); });
+ if (schemaElm) {
+ switch (schemaElm['params']) {
+ case undefined:
+ break;
+ case 'timestamp':
+ var timestamp = retVal.toString().substring(0, 8);
+ var date = new Date(parseInt(timestamp, 16) * 1000);
+ retVal = date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
+ break;
+ default:
+ retVal = $scope.dataEventFunctions[schemaElm['params']](record);
+ }
+ }
+ }
+ return retVal;
+ };
+ function updateObject(aFieldName, portion, fn) {
+ var fieldDetails = splitFieldName(aFieldName);
+ if (fieldDetails.length > 1) {
+ updateArrayOrObject(fieldDetails[1], portion[fieldDetails[0]], fn);
+ }
+ else if (portion[fieldDetails[0]]) {
+ var theValue = portion[fieldDetails[0]];
+ // Strip out empty objects here (in case anyone added to an array and didn't populate it)
+ if (angular.isArray(theValue)) {
+ for (var i = theValue.length - 1; i >= 0; i--) {
+ var type = typeof theValue[i];
+ if (type === 'undefined' || (type === 'object' && Object.keys(theValue[i]).length === 0)) {
+ theValue.splice(i, 1);
+ }
+ }
+ }
+ portion[fieldDetails[0]] = fn(theValue);
+ }
+ }
+ function updateArrayOrObject(aFieldName, portion, fn) {
+ if (portion !== undefined) {
+ if (angular.isArray(portion)) {
+ for (var i = 0; i < portion.length; i++) {
+ updateObject(aFieldName, portion[i], fn);
+ }
+ }
+ else {
+ updateObject(aFieldName, portion, fn);
+ }
+ }
+ }
+ var simpleArrayNeedsX = function (aSchema) {
+ var result = false;
+ if (aSchema.needsX) {
+ result = true;
+ }
+ else if (!aSchema.directive) {
+ if (aSchema.type === 'text') {
+ result = true;
+ }
+ else if (aSchema.type === 'select' && !aSchema.ids) {
+ result = true;
+ }
+ }
+ return result;
+ };
+ /* Look up a conversion set up by a plugin */
+ function getConversionObject(scope, entryName, schemaName) {
+ var conversions = scope.conversions;
+ if (schemaName) {
+ conversions = conversions[schemaName] || {};
+ }
+ return conversions[entryName];
+ }
+ // Convert mongodb json to what we use in the browser, for example {_id:'xxx', array:['item 1'], lookup:'012abcde'} to {_id:'xxx', array:[{x:'item 1'}], lookup:'List description for 012abcde'}
+ // This will currently only work for a single level of nesting (conversionObject will not go down further without amendment, and offset needs to be an array, at least)
+ var convertToAngularModel = function (schema, anObject, prefixLength, $scope, schemaName, master, offset) {
+ master = master || anObject;
+ for (var i = 0; i < schema.length; i++) {
+ var schemaEntry = schema[i];
+ var fieldName = schemaEntry.name.slice(prefixLength);
+ var fieldValue = getData(anObject, fieldName);
+ if (schemaEntry.schema) {
+ if (fieldValue) {
+ for (var j = 0; j < fieldValue.length; j++) {
+ fieldValue[j] = convertToAngularModel(schemaEntry.schema, fieldValue[j], prefixLength + 1 + fieldName.length, $scope, fieldName, master, j);
+ }
+ }
+ }
+ else {
+ // Convert {array:['item 1']} to {array:[{x:'item 1'}]}
+ var thisField = getListData($scope, anObject, fieldName);
+ if (schemaEntry.array && simpleArrayNeedsX(schemaEntry) && thisField) {
+ for (var k = 0; k < thisField.length; k++) {
+ thisField[k] = { x: thisField[k] };
+ }
+ }
+ // Convert {lookup:'012abcde'} to {lookup:'List description for 012abcde'}
+ var idList = $scope[suffixCleanId(schemaEntry, '_ids')];
+ var thisConversion = void 0;
+ if (fieldValue && idList && idList.length > 0) {
+ if (fieldName.indexOf('.') !== -1) {
+ throw new Error('Trying to directly assign to a nested field 332');
+ } // Not sure that this can happen, but put in a runtime test
+ anObject[fieldName] = convertForeignKeys(schemaEntry, fieldValue, $scope[suffixCleanId(schemaEntry, 'Options')], idList);
+ }
+ else if (schemaEntry.select2) {
+ // Do nothing with these - handled elsewhere (and deprecated)
+ console.log('fng-select2 is deprecated - use fng-ui-select instead');
+ void (schemaEntry.select2);
+ }
+ else if (fieldValue && (thisConversion = getConversionObject($scope, fieldName, schemaName)) &&
+ thisConversion.fngajax &&
+ !thisConversion.noconvert) {
+ thisConversion.fngajax(fieldValue, schemaEntry, function (updateEntry, value) {
+ // Update the master and (preserving pristine if appropriate) the record
+ setData(master, updateEntry.name, offset, value);
+ preservePristine(angular.element('#' + updateEntry.id), function () {
+ setData($scope.record, updateEntry.name, offset, value);
+ });
+ });
+ }
+ }
+ }
+ return anObject;
+ };
+ // Convert foreign keys into their display for selects
+ // Called when the model is read and when the lookups are read
+ // No support for nested schemas here as it is called from convertToAngularModel which does that
+ function convertForeignKeys(schemaElement, input, values, ids) {
+ if (schemaElement.array) {
+ var returnArray = [];
+ var needsX = !schemaElement.directive || simpleArrayNeedsX(schemaElement);
+ for (var j = 0; j < input.length; j++) {
+ var val = input[j];
+ if (val && val.x) {
+ val = val.x;
+ }
+ var lookup = convertIdToListValue(val, ids, values, schemaElement.name);
+ if (needsX) {
+ lookup = { x: lookup };
+ }
+ returnArray.push(lookup);
+ }
+ return returnArray;
+ }
+ else if (schemaElement.select2) {
+ return { id: input, text: convertIdToListValue(input, ids, values, schemaElement.name) };
+ }
+ else {
+ return convertIdToListValue(input, ids, values, schemaElement.name);
+ }
+ }
+ // Convert ids into their foreign keys
+ // Called when saving the model
+ // No support for nested schemas here as it is called from convertToMongoModel which does that
+ function convertToForeignKeys(schemaElement, input, values, ids) {
+ if (schemaElement.array) {
+ var returnArray = [];
+ for (var j = 0; j < input.length; j++) {
+ returnArray.push(convertListValueToId(input[j], values, ids, schemaElement.name));
+ }
+ return returnArray;
+ }
+ else {
+ return convertListValueToId(input, values, ids, schemaElement.name);
+ }
+ }
+ var convertListValueToId = function (value, valuesArray, idsArray, fname) {
+ var textToConvert = _.isObject(value) ? (value.x || value.text) : value;
+ if (textToConvert && textToConvert.match(/^[0-9a-f]{24}$/)) {
+ return textToConvert; // a plugin probably added this
+ }
+ else {
+ var index = valuesArray.indexOf(textToConvert);
+ if (index === -1) {
+ throw new Error('convertListValueToId: Invalid data - value ' + textToConvert + ' not found in ' + valuesArray + ' processing ' + fname);
+ }
+ return idsArray[index];
+ }
+ };
+ var preservePristine = function preservePristine(element, fn) {
+ // stop the form being set to dirty when a fn is called
+ // Use when the record (and master) need to be updated by lookup values displayed asynchronously
+ var modelController = element.inheritedData('$ngModelController');
+ var isClean = (modelController && modelController.$pristine);
+ if (isClean) {
+ // fake it to dirty here and reset after call to fn
+ modelController.$pristine = false;
+ }
+ fn();
+ if (isClean) {
+ modelController.$pristine = true;
+ }
+ };
+ var convertIdToListValue = function convertIdToListValue(id, idsArray, valuesArray, fname) {
+ if (typeof (id) === 'object') {
+ id = id.id;
+ }
+ var index = idsArray.indexOf(id);
+ if (index === -1) {
+ throw new Error('convertIdToListValue: Invalid data - id ' + id + ' not found in ' + idsArray + ' processing ' + fname);
+ }
+ return valuesArray[index];
+ };
+ var processServerData = function processServerData(recordFromServer, $scope, ctrlState) {
+ ctrlState.master = convertToAngularModel($scope.formSchema, recordFromServer, 0, $scope);
+ $scope.phase = 'ready';
+ $scope.cancel();
+ };
+ function fillFormFromBackendCustomSchema(schema, $scope, formGeneratorInstance, recordHandlerInstance, ctrlState) {
+ var listOnly = (!$scope.id && !$scope.newRecord);
+ // passing null for formSchema parameter prevents all the work being done when we are just after the list data,
+ // but should be removed when/if formschemas are cached
+ formGeneratorInstance.handleSchema('Main ' + $scope.modelName, schema, listOnly ? null : $scope.formSchema, $scope.listSchema, '', true, $scope, ctrlState);
+ if (listOnly) {
+ ctrlState.allowLocationChange = true;
+ }
+ else {
+ var force = true;
+ if (!$scope.newRecord) {
+ $scope.dropConversionWatcher = $scope.$watchCollection('conversions', function (newValue, oldValue) {
+ if (newValue !== oldValue && $scope.originalData) {
+ processServerData($scope.originalData, $scope, ctrlState);
+ }
+ });
+ }
+ $scope.$watch('record', function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (Object.keys(oldValue).length > 0 && $scope.dropConversionWatcher) {
+ $scope.dropConversionWatcher(); // Don't want to convert changed data
+ $scope.dropConversionWatcher = null;
+ }
+ force = formGeneratorInstance.updateDataDependentDisplay(newValue, oldValue, force, $scope);
+ }
+ }, true);
+ if ($scope.id) {
+ // Going to read a record
+ if (typeof $scope.dataEventFunctions.onBeforeRead === 'function') {
+ $scope.dataEventFunctions.onBeforeRead($scope.id, function (err) {
+ if (err) {
+ $scope.showError(err);
+ }
+ else {
+ recordHandlerInstance.readRecord($scope, ctrlState);
+ }
+ });
+ }
+ else {
+ recordHandlerInstance.readRecord($scope, ctrlState);
+ }
+ }
+ else {
+ // New record
+ ctrlState.master = {};
+ var passedRecord = $scope.initialiseNewRecord || $location.$$search.r;
+ if (passedRecord) {
+ try {
+ ctrlState.master = JSON.parse(passedRecord);
+ // Although this is a new record we are making it dirty from the url so we need to $setDirty
+ $scope.$on('fngCancel', function () {
+ setTimeout(function () {
+ if ($scope[$scope.topLevelFormName]) {
+ $scope[$scope.topLevelFormName].$setDirty();
+ }
+ }, 2); // Has to fire after the setPristime timeout.
+ });
+ }
+ catch (e) {
+ console.log('Error parsing specified record : ' + e.message);
+ }
+ }
+ if (typeof $scope.dataEventFunctions.onInitialiseNewRecord === 'function') {
+ $scope.dataEventFunctions.onInitialiseNewRecord(ctrlState.master);
+ }
+ $scope.phase = 'ready';
+ $scope.cancel();
+ }
+ }
+ }
+ function handleError($scope) {
+ return function (response) {
+ if ([200, 400].indexOf(response.status) !== -1) {
+ var errorMessage = '';
+ for (var errorField in response.data.errors) {
+ if (response.data.errors.hasOwnProperty(errorField)) {
+ errorMessage += '
' + $filter('titleCase')(errorField) + ': ';
+ switch (response.data.errors[errorField].type) {
+ case 'enum':
+ errorMessage += 'You need to select from the list of values';
+ break;
+ default:
+ errorMessage += response.data.errors[errorField].message;
+ break;
+ }
+ errorMessage += '';
+ }
+ }
+ if (errorMessage.length > 0) {
+ errorMessage = response.data.message + '
';
+ }
+ else {
+ errorMessage = response.data.message || 'Error! Sorry - No further details available.';
+ }
+ $scope.showError(errorMessage);
+ }
+ else {
+ $scope.showError(response.status + ' ' + JSON.stringify(response.data));
+ }
+ };
+ }
+ function handleIncomingData(data, $scope, ctrlState) {
+ ctrlState.allowLocationChange = false;
+ $scope.phase = 'reading';
+ if (typeof $scope.dataEventFunctions.onAfterRead === 'function') {
+ $scope.dataEventFunctions.onAfterRead(data);
+ }
+ $scope.originalData = data;
+ processServerData(data, $scope, ctrlState);
+ }
+ return {
+ readRecord: function readRecord($scope, ctrlState) {
+ // TODO Consider using $parse for this - http://bahmutov.calepin.co/angularjs-parse-hacks.html
+ SubmissionsService.readRecord($scope.modelName, $scope.id)
+ .then(function (response) {
+ var data = response.data;
+ if (data.success === false) {
+ $location.path('/404');
+ }
+ else if (response.master) {
+ ctrlState.allowLocationChange = false;
+ $scope.phase = 'ready';
+ $scope.record = angular.copy(response.data);
+ ctrlState.master = angular.copy(response.master);
+ if (response.changed) {
+ $timeout(function () {
+ $scope[$scope.topLevelFormName].$setDirty();
+ });
+ }
+ else {
+ $timeout($scope.setPristine);
+ }
+ }
+ else {
+ handleIncomingData(data, $scope, ctrlState);
+ }
+ }, $scope.handleHttpError);
+ },
+ scrollTheList: function scrollTheList($scope) {
+ var pagesLoaded = $scope.pagesLoaded;
+ SubmissionsService.getPagedAndFilteredList($scope.modelName, {
+ aggregate: $location.$$search.a,
+ find: $location.$$search.f,
+ limit: $scope.pageSize,
+ skip: pagesLoaded * $scope.pageSize,
+ order: $location.$$search.o
+ })
+ .then(function (response) {
+ var data = response.data;
+ if (angular.isArray(data)) {
+ // I have seen an intermittent problem where a page is requested twice
+ if (pagesLoaded === $scope.pagesLoaded) {
+ $scope.pagesLoaded++;
+ $scope.recordList = $scope.recordList.concat(data);
+ }
+ else {
+ console.log('DEBUG: infinite scroll component asked for a page twice');
+ }
+ }
+ else {
+ $scope.showError(data, 'Invalid query');
+ }
+ }, $scope.handleHttpError);
+ },
+ // TODO: Do we need model here? Can we not infer it from scope?
+ deleteRecord: function deleteRecord(model, id, $scope, ctrlState) {
+ SubmissionsService.deleteRecord(model, id)
+ .then(function () {
+ if (typeof $scope.dataEventFunctions.onAfterDelete === 'function') {
+ $scope.dataEventFunctions.onAfterDelete(ctrlState.master);
+ }
+ routingService.redirectTo()('list', $scope, $location);
+ });
+ },
+ updateDocument: function updateDocument(dataToSave, options, $scope, ctrlState) {
+ $scope.phase = 'updating';
+ SubmissionsService.updateRecord($scope.modelName, $scope.id, dataToSave)
+ .then(function (response) {
+ var data = response.data;
+ if (data.success !== false) {
+ if (typeof $scope.dataEventFunctions.onAfterUpdate === 'function') {
+ $scope.dataEventFunctions.onAfterUpdate(data, ctrlState.master);
+ }
+ if (options.redirect) {
+ if (options.allowChange) {
+ ctrlState.allowLocationChange = true;
+ }
+ $window.location = options.redirect;
+ }
+ else {
+ handleIncomingData(data, $scope, ctrlState);
+ $scope.setPristine(false);
+ }
+ }
+ else {
+ $scope.showError(data);
+ }
+ }, $scope.handleHttpError);
+ },
+ createNew: function createNew(dataToSave, options, $scope) {
+ SubmissionsService.createRecord($scope.modelName, dataToSave)
+ .then(function (response) {
+ var data = response.data;
+ if (data.success !== false) {
+ if (typeof $scope.dataEventFunctions.onAfterCreate === 'function') {
+ $scope.dataEventFunctions.onAfterCreate(data);
+ }
+ if (options.redirect) {
+ $window.location = options.redirect;
+ }
+ else {
+ routingService.redirectTo()('edit', $scope, $location, data._id);
+ }
+ }
+ else {
+ $scope.showError(data);
+ }
+ }, $scope.handleHttpError);
+ },
+ getListData: getListData,
+ suffixCleanId: suffixCleanId,
+ setData: setData,
+ setUpSelectOptions: function setUpSelectOptions(lookupCollection, schemaElement, $scope, ctrlState, handleSchema) {
+ var optionsList = $scope[schemaElement.options] = [];
+ var idList = $scope[schemaElement.ids] = [];
+ SchemasService.getSchema(lookupCollection)
+ .then(function (response) {
+ var data = response.data;
+ var listInstructions = [];
+ handleSchema('Lookup ' + lookupCollection, data, null, listInstructions, '', false, $scope, ctrlState);
+ var dataRequest;
+ if (typeof schemaElement.filter !== 'undefined' && schemaElement.filter) {
+ dataRequest = SubmissionsService.getPagedAndFilteredList(lookupCollection, schemaElement.filter);
+ }
+ else {
+ dataRequest = SubmissionsService.getAll(lookupCollection);
+ }
+ dataRequest
+ .then(function (response) {
+ var data = response.data;
+ if (data) {
+ for (var i = 0; i < data.length; i++) {
+ var option = '';
+ for (var j = 0; j < listInstructions.length; j++) {
+ var thisVal = data[i][listInstructions[j].name];
+ option += thisVal ? thisVal + ' ' : '';
+ }
+ option = option.trim();
+ var pos = _.sortedIndex(optionsList, option);
+ // handle dupes (ideally people will use unique indexes to stop them but...)
+ if (optionsList[pos] === option) {
+ option = option + ' (' + data[i]._id + ')';
+ pos = _.sortedIndex(optionsList, option);
+ }
+ optionsList.splice(pos, 0, option);
+ idList.splice(pos, 0, data[i]._id);
+ }
+ updateRecordWithLookupValues(schemaElement, $scope, ctrlState);
+ }
+ });
+ });
+ },
+ preservePristine: preservePristine,
+ // Reverse the process of convertToAngularModel
+ convertToMongoModel: function convertToMongoModel(schema, anObject, prefixLength, $scope, schemaName) {
+ function convertLookup(lookup, conversionInst) {
+ var retVal;
+ if (conversionInst && conversionInst.fngajax) {
+ if (lookup) {
+ retVal = lookup.id || lookup;
+ }
+ }
+ else if (lookup) {
+ retVal = lookup.text || (lookup.x ? lookup.x.text : lookup);
+ }
+ return retVal;
+ }
+ for (var i = 0; i < schema.length; i++) {
+ var fieldname = schema[i].name.slice(prefixLength);
+ var thisField = getListData($scope, anObject, fieldname);
+ if (schema[i].schema) {
+ if (thisField) {
+ for (var j = 0; j < thisField.length; j++) {
+ thisField[j] = convertToMongoModel(schema[i].schema, thisField[j], prefixLength + 1 + fieldname.length, $scope, fieldname);
+ }
+ }
+ }
+ else {
+ // Convert {array:[{x:'item 1'}]} to {array:['item 1']}
+ if (schema[i].array && simpleArrayNeedsX(schema[i]) && thisField) {
+ for (var k = 0; k < thisField.length; k++) {
+ thisField[k] = thisField[k].x;
+ }
+ }
+ // Convert {lookup:'List description for 012abcde'} to {lookup:'012abcde'}
+ var idList = $scope[suffixCleanId(schema[i], '_ids')];
+ var thisConversion = void 0;
+ if (idList && idList.length > 0) {
+ updateObject(fieldname, anObject, function (value) {
+ return convertToForeignKeys(schema[i], value, $scope[suffixCleanId(schema[i], 'Options')], idList);
+ });
+ }
+ else if (thisConversion = getConversionObject($scope, fieldname, schemaName)) {
+ var lookup = getData(anObject, fieldname, null);
+ var newVal;
+ if (schema[i].array) {
+ newVal = [];
+ if (lookup) {
+ for (var n = 0; n < lookup.length; n++) {
+ newVal[n] = convertLookup(lookup[n], thisConversion);
+ }
+ }
+ }
+ else {
+ newVal = convertLookup(lookup, thisConversion);
+ }
+ setData(anObject, fieldname, null, newVal);
+ }
+ }
+ }
+ return anObject;
+ },
+ convertIdToListValue: convertIdToListValue,
+ handleError: handleError,
+ decorateScope: function decorateScope($scope, $uibModal, recordHandlerInstance, ctrlState) {
+ $scope.handleHttpError = handleError($scope);
+ $scope.cancel = function () {
+ angular.copy(ctrlState.master, $scope.record);
+ $scope.$broadcast('fngCancel', $scope);
+ // Let call backs etc resolve in case they dirty form, then clean it
+ $timeout($scope.setPristine);
+ };
+ //listener for any child scopes to display messages
+ // pass like this:
+ // scope.$emit('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
+ // or
+ // scope.$broadcast('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
+ $scope.$on('showErrorMessage', function (event, args) {
+ $scope.showError(args.body, args.title);
+ });
+ $scope.showError = function (error, alertTitle) {
+ $scope.alertTitle = alertTitle ? alertTitle : 'Error!';
+ if (typeof error === 'string') {
+ $scope.errorMessage = error;
+ }
+ else if (error.message && typeof error.message === 'string') {
+ $scope.errorMessage = error.message;
+ }
+ else if (error.data && error.data.message) {
+ $scope.errorMessage = error.data.message;
+ }
+ else {
+ try {
+ $scope.errorMessage = JSON.stringify(error);
+ }
+ catch (e) {
+ $scope.errorMessage = error;
+ }
+ }
+ };
+ $scope.dismissError = function () {
+ delete $scope.errorMessage;
+ delete $scope.alertTitle;
+ };
+ $scope.prepareForSave = function (cb) {
+ //Convert the lookup values into ids
+ var dataToSave = recordHandlerInstance.convertToMongoModel($scope.formSchema, angular.copy($scope.record), 0, $scope);
+ if ($scope.id) {
+ if (typeof $scope.dataEventFunctions.onBeforeUpdate === 'function') {
+ $scope.dataEventFunctions.onBeforeUpdate(dataToSave, ctrlState.master, function (err) {
+ if (err) {
+ cb(err);
+ }
+ else {
+ cb(null, dataToSave);
+ }
+ });
+ }
+ else {
+ cb(null, dataToSave);
+ }
+ }
+ else {
+ if (typeof $scope.dataEventFunctions.onBeforeCreate === 'function') {
+ $scope.dataEventFunctions.onBeforeCreate(dataToSave, function (err) {
+ if (err) {
+ cb(err);
+ }
+ else {
+ cb(null, dataToSave);
+ }
+ });
+ }
+ else {
+ cb(null, dataToSave);
+ }
+ }
+ };
+ $scope.save = function (options) {
+ options = options || {};
+ $scope.prepareForSave(function (err, dataToSave) {
+ if (err) {
+ if (err !== '_update_handled_') {
+ $scope.showError(err);
+ }
+ }
+ else if ($scope.id) {
+ recordHandlerInstance.updateDocument(dataToSave, options, $scope, ctrlState);
+ }
+ else {
+ recordHandlerInstance.createNew(dataToSave, options, $scope);
+ }
+ });
+ };
+ $scope.newClick = function () {
+ routingService.redirectTo()('new', $scope, $location);
+ };
+ $scope.$on('$locationChangeStart', function (event, next) {
+ var changed = !$scope.isCancelDisabled();
+ var curPath = window.location.href.split('/');
+ var nextPath = next.split('/');
+ var tabChangeOnly = true;
+ var i = 0;
+ do {
+ i += 1;
+ if (curPath[i] !== nextPath[i]) {
+ tabChangeOnly = false;
+ }
+ } while (tabChangeOnly && curPath[i] !== 'edit');
+ if (tabChangeOnly) {
+ // let dataToReturn = recordHandlerInstance.convertToMongoModel($scope.formSchema, angular.copy($scope.record), 0, $scope);
+ SubmissionsService.setUpForTabChange($scope.modelName, $scope.id, $scope.record, ctrlState.master, changed);
+ }
+ else if (!ctrlState.allowLocationChange && changed) {
+ event.preventDefault();
+ var modalInstance = $uibModal.open({
+ template: '' +
+ '
' +
+ '
Would you like to save your changes?
' +
+ '
' +
+ '',
+ controller: 'SaveChangesModalCtrl',
+ backdrop: 'static'
+ });
+ modalInstance.result.then(function (result) {
+ if (result) {
+ $scope.save({ redirect: next, allowChange: true }); // save changes
+ }
+ else {
+ ctrlState.allowLocationChange = true;
+ $window.location = next;
+ }
+ });
+ }
+ });
+ $scope.deleteClick = function () {
+ if ($scope.record._id) {
+ var confirmDelete = void 0;
+ if ($scope.unconfirmedDelete) {
+ confirmDelete = Promise.resolve(true);
+ }
+ else {
+ var modalInstance = $uibModal.open({
+ template: '' +
+ '
' +
+ '
Are you sure you want to delete this record?
' +
+ '
' +
+ '',
+ controller: 'SaveChangesModalCtrl',
+ backdrop: 'static'
+ });
+ confirmDelete = modalInstance.result;
+ }
+ confirmDelete.then(function (result) {
+ if (result) {
+ if (typeof $scope.dataEventFunctions.onBeforeDelete === 'function') {
+ $scope.dataEventFunctions.onBeforeDelete(ctrlState.master, function (err) {
+ if (err) {
+ if (err !== '_delete_handled_') {
+ $scope.showError(err);
+ }
+ }
+ else {
+ recordHandlerInstance.deleteRecord($scope.modelName, $scope.id, $scope, ctrlState);
+ }
+ });
+ }
+ else {
+ recordHandlerInstance.deleteRecord($scope.modelName, $scope.id, $scope, ctrlState);
+ }
+ }
+ });
+ }
+ };
+ $scope.isCancelDisabled = function () {
+ if (typeof $scope.disableFunctions.isCancelDisabled === 'function') {
+ return $scope.disableFunctions.isCancelDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ }
+ else {
+ return $scope[$scope.topLevelFormName] && $scope[$scope.topLevelFormName].$pristine;
+ }
+ };
+ $scope.isSaveDisabled = function () {
+ if (typeof $scope.disableFunctions.isSaveDisabled === 'function') {
+ return $scope.disableFunctions.isSaveDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ }
+ else {
+ return ($scope[$scope.topLevelFormName] && ($scope[$scope.topLevelFormName].$invalid || $scope[$scope.topLevelFormName].$pristine));
+ }
+ };
+ $scope.isDeleteDisabled = function () {
+ if (typeof $scope.disableFunctions.isDeleteDisabled === 'function') {
+ return $scope.disableFunctions.isDeleteDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ }
+ else {
+ return (!$scope.id);
+ }
+ };
+ $scope.isNewDisabled = function () {
+ if (typeof $scope.disableFunctions.isNewDisabled === 'function') {
+ return $scope.disableFunctions.isNewDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ }
+ else {
+ return false;
+ }
+ };
+ $scope.disabledText = function (localStyling) {
+ var text = '';
+ if ($scope.isSaveDisabled) {
+ text = 'This button is only enabled when the form is complete and valid. Make sure all required inputs are filled in. ' + localStyling;
+ }
+ return text;
+ };
+ $scope.getVal = function (expression, index) {
+ if (expression.indexOf('$index') === -1 || typeof index !== 'undefined') {
+ expression = expression.replace(/\$index/g, index);
+ return $scope.$eval('record.' + expression);
+ }
+ //else {
+ // Used to show error here, but angular seems to call before record is populated sometimes
+ // throw new Error('Invalid expression in getVal(): ' + expression);
+ //}
+ };
+ $scope.sortableOptions = {
+ update: function () {
+ if ($scope.topLevelFormName) {
+ $scope[$scope.topLevelFormName].$setDirty();
+ }
+ }
+ };
+ },
+ fillFormFromBackendCustomSchema: fillFormFromBackendCustomSchema,
+ fillFormWithBackendSchema: function fillFormWithBackendSchema($scope, formGeneratorInstance, recordHandlerInstance, ctrlState) {
+ SchemasService.getSchema($scope.modelName, $scope.formName)
+ .then(function (response) {
+ var schema = response.data;
+ fillFormFromBackendCustomSchema(schema, $scope, formGeneratorInstance, recordHandlerInstance, ctrlState);
+ }, $scope.handleHttpError);
+ }
+ };
+ }
+ services.recordHandler = recordHandler;
+ })(services = fng.services || (fng.services = {}));
+})(fng || (fng = {}));
+//# sourceMappingURL=record-handler.js.map
\ No newline at end of file
diff --git a/src/client/js/services/record-handler.js.map b/src/client/js/services/record-handler.js.map
new file mode 100644
index 00000000..1f7e6c56
--- /dev/null
+++ b/src/client/js/services/record-handler.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"record-handler.js","sourceRoot":"","sources":["record-handler.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/src/client/js/services/record-handler.ts b/src/client/js/services/record-handler.ts
new file mode 100644
index 00000000..befa6397
--- /dev/null
+++ b/src/client/js/services/record-handler.ts
@@ -0,0 +1,933 @@
+///
+
+module fng.services {
+ /**
+ * Operations on a whole record
+ *
+ * All methods should be state-less
+ *
+ */
+
+ /*@ngInject*/
+ export function recordHandler($http, $location, $window, $filter, $timeout, routingService, SubmissionsService, SchemasService) : fng.IRecordHandler {
+
+ var suffixCleanId = function suffixCleanId(inst, suffix) {
+ return (inst.id || 'f_' + inst.name).replace(/\./g, '_') + suffix;
+ };
+
+ var walkTree = function (object, fieldname, element) {
+ // Walk through subdocs to find the required key
+ // for instance walkTree(master,'address.street.number',element)
+ // called by getData and setData
+
+ // element is used when accessing in the context of a input, as the id (like exams-2-grader)
+ // gives us the element of an array (one level down only for now). Leaving element blank returns the whole array
+ var parts = fieldname.split('.'),
+ higherLevels = parts.length - 1,
+ workingRec = object;
+ for (var i = 0; i < higherLevels; i++) {
+ if (!workingRec) {
+ throw new Error(`walkTree failed: Object = ${object}, fieldname = ${fieldname}, i = ${i}`);
+ }
+ if (angular.isArray(workingRec)) {
+ workingRec = _.map(workingRec, function (obj) {
+ return obj[parts[i]];
+ });
+ } else {
+ workingRec = workingRec[parts[i]];
+ }
+ if (angular.isArray(workingRec) && typeof element !== 'undefined') {
+ if (element.scope && typeof element.scope === 'function') {
+ // If we come across an array we need to find the correct position, if we have an element
+ workingRec = workingRec[element.scope().$index];
+ } else if (typeof element === 'number') {
+ workingRec = workingRec[element];
+ } else {
+ throw new Error('Unsupported element type in walkTree ' + fieldname)
+ }
+ }
+ if (!workingRec) {
+ break;
+ }
+ }
+ return {
+ lastObject: workingRec,
+ key: workingRec ? parts[higherLevels] : undefined
+ };
+ };
+
+ var setData = function setData(object, fieldname, element, value) {
+ var leafData = walkTree(object, fieldname, element);
+
+ if (leafData.lastObject && leafData.key) {
+ if (angular.isArray(leafData.lastObject)) {
+ for (var i = 0; i < leafData.lastObject.length; i++) {
+ leafData.lastObject[i][leafData.key] = value[i];
+ }
+ } else {
+ leafData.lastObject[leafData.key] = value;
+ }
+ }
+ };
+
+ var getData = function (object, fieldname, element?:any) {
+ var leafData = walkTree(object, fieldname, element);
+ var retVal;
+ if (leafData.lastObject && leafData.key) {
+ if (angular.isArray(leafData.lastObject)) {
+ retVal = _.map(leafData.lastObject, function (obj) {
+ return obj[leafData.key];
+ });
+ } else {
+ retVal = leafData.lastObject[leafData.key];
+ }
+ }
+ return retVal;
+ };
+
+ var updateRecordWithLookupValues = function (schemaElement, $scope, ctrlState) {
+ // Update the master and the record with the lookup values, master first
+ if (!$scope.topLevelFormName || $scope[$scope.topLevelFormName].$pristine) {
+ updateObject(schemaElement.name, ctrlState.master, function (value) {
+ return convertForeignKeys(schemaElement, value, $scope[suffixCleanId(schemaElement, 'Options')], $scope[suffixCleanId(schemaElement, '_ids')]);
+ });
+ // Then copy the converted keys from master into record
+ var newVal = getData(ctrlState.master, schemaElement.name);
+ if (newVal) {
+ setData($scope.record, schemaElement.name, undefined, newVal);
+ }
+ }
+ };
+
+// Split a field name into the next level and all following levels
+ function splitFieldName(aFieldName) {
+ var nesting = aFieldName.split('.'),
+ result = [nesting[0]];
+
+ if (nesting.length > 1) {
+ result.push(nesting.slice(1).join('.'));
+ }
+
+ return result;
+ }
+
+ var getListData = function getListData($scope, record, fieldName, listSchema=null) {
+ var retVal = record;
+ var nests = fieldName.split('.');
+ for (var i = 0; i < nests.length; i++) {
+ if (retVal !== undefined && retVal !== null && nests && nests[i]) {
+ retVal = retVal[nests[i]];
+ }
+ }
+ if (retVal === undefined) {
+ retVal = '';
+ }
+
+ if (retVal && listSchema) {
+ // Convert list fields as per instructions in params (ideally should be the same as what is found in data_form getListFields
+ var schemaElm = _.find(listSchema, elm => (elm['name'] === fieldName));
+ if (schemaElm) {
+ switch (schemaElm['params']) {
+ case undefined :
+ break;
+ case 'timestamp' :
+ var timestamp = retVal.toString().substring(0,8);
+ var date = new Date( parseInt( timestamp, 16 ) * 1000 );
+ retVal = date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
+ break;
+ default:
+ retVal = $scope.dataEventFunctions[schemaElm['params']](record);
+ }
+ }
+ }
+ return retVal;
+ };
+
+ function updateObject(aFieldName, portion, fn) {
+ var fieldDetails = splitFieldName(aFieldName);
+
+ if (fieldDetails.length > 1) {
+ updateArrayOrObject(fieldDetails[1], portion[fieldDetails[0]], fn);
+ } else if (portion[fieldDetails[0]]) {
+ var theValue = portion[fieldDetails[0]];
+
+ // Strip out empty objects here (in case anyone added to an array and didn't populate it)
+ if (angular.isArray(theValue)) {
+ for (var i = theValue.length - 1; i >= 0; i--) {
+ var type = typeof theValue[i];
+ if (type === 'undefined' || (type === 'object' && Object.keys(theValue[i]).length === 0)) {
+ theValue.splice(i, 1);
+ }
+ }
+ }
+ portion[fieldDetails[0]] = fn(theValue);
+ }
+ }
+
+ function updateArrayOrObject(aFieldName, portion, fn) {
+ if (portion !== undefined) {
+ if (angular.isArray(portion)) {
+ for (var i = 0; i < portion.length; i++) {
+ updateObject(aFieldName, portion[i], fn);
+ }
+ } else {
+ updateObject(aFieldName, portion, fn);
+ }
+ }
+ }
+
+ var simpleArrayNeedsX = function (aSchema) {
+ var result = false;
+
+ if (aSchema.needsX) {
+ result = true;
+ } else if (!aSchema.directive) {
+ if (aSchema.type === 'text') {
+ result = true;
+ } else if (aSchema.type === 'select' && !aSchema.ids) {
+ result = true;
+ }
+ }
+ return result;
+ };
+
+ /* Look up a conversion set up by a plugin */
+ function getConversionObject(scope: any, entryName: string, schemaName? : string) : any {
+ let conversions = scope.conversions;
+ if (schemaName) {
+ conversions = conversions[schemaName] || {};
+ }
+ return conversions[entryName];
+ }
+
+
+ // Convert mongodb json to what we use in the browser, for example {_id:'xxx', array:['item 1'], lookup:'012abcde'} to {_id:'xxx', array:[{x:'item 1'}], lookup:'List description for 012abcde'}
+ // This will currently only work for a single level of nesting (conversionObject will not go down further without amendment, and offset needs to be an array, at least)
+ var convertToAngularModel = function (schema, anObject, prefixLength, $scope, schemaName? : string, master?, offset?: number) {
+ master = master || anObject;
+ for (var i = 0; i < schema.length; i++) {
+ var schemaEntry = schema[i];
+ var fieldName = schemaEntry.name.slice(prefixLength);
+ var fieldValue = getData(anObject, fieldName);
+ if (schemaEntry.schema) {
+ if (fieldValue) {
+ for (var j = 0; j < fieldValue.length; j++) {
+ fieldValue[j] = convertToAngularModel(schemaEntry.schema, fieldValue[j], prefixLength + 1 + fieldName.length, $scope, fieldName, master, j);
+ }
+ }
+ } else {
+ // Convert {array:['item 1']} to {array:[{x:'item 1'}]}
+ var thisField = getListData($scope, anObject, fieldName);
+ if (schemaEntry.array && simpleArrayNeedsX(schemaEntry) && thisField) {
+ for (var k = 0; k < thisField.length; k++) {
+ thisField[k] = {x: thisField[k]};
+ }
+ }
+
+ // Convert {lookup:'012abcde'} to {lookup:'List description for 012abcde'}
+ var idList = $scope[suffixCleanId(schemaEntry, '_ids')];
+ let thisConversion: any;
+ if (fieldValue && idList && idList.length > 0) {
+ if (fieldName.indexOf('.') !== -1) {
+ throw new Error('Trying to directly assign to a nested field 332');
+ } // Not sure that this can happen, but put in a runtime test
+ anObject[fieldName] = convertForeignKeys(schemaEntry, fieldValue, $scope[suffixCleanId(schemaEntry, 'Options')], idList);
+ } else if (schemaEntry.select2) {
+ // Do nothing with these - handled elsewhere (and deprecated)
+ console.log('fng-select2 is deprecated - use fng-ui-select instead');
+ void(schemaEntry.select2);
+ } else if (fieldValue && (thisConversion = getConversionObject($scope, fieldName, schemaName)) &&
+ thisConversion.fngajax &&
+ !thisConversion.noconvert
+ ) {
+ thisConversion.fngajax(fieldValue, schemaEntry, function (updateEntry, value) {
+ // Update the master and (preserving pristine if appropriate) the record
+ setData(master, updateEntry.name, offset, value);
+ preservePristine( angular.element('#' + updateEntry.id), function () {
+ setData($scope.record, updateEntry.name, offset, value);
+ });
+ });
+ }
+ }
+ }
+ return anObject;
+ };
+
+// Convert foreign keys into their display for selects
+// Called when the model is read and when the lookups are read
+
+// No support for nested schemas here as it is called from convertToAngularModel which does that
+ function convertForeignKeys(schemaElement, input, values, ids) {
+ if (schemaElement.array) {
+ var returnArray = [];
+ var needsX = !schemaElement.directive || simpleArrayNeedsX(schemaElement);
+ for (var j = 0; j < input.length; j++) {
+ var val = input[j];
+ if (val && val.x) {
+ val = val.x;
+ }
+ var lookup = convertIdToListValue(val, ids, values, schemaElement.name);
+ if (needsX) {
+ lookup = {x: lookup};
+ }
+ returnArray.push(lookup);
+ }
+ return returnArray;
+ } else if (schemaElement.select2) {
+ return {id: input, text: convertIdToListValue(input, ids, values, schemaElement.name)};
+ } else {
+ return convertIdToListValue(input, ids, values, schemaElement.name);
+ }
+ }
+
+// Convert ids into their foreign keys
+// Called when saving the model
+
+// No support for nested schemas here as it is called from convertToMongoModel which does that
+ function convertToForeignKeys(schemaElement, input, values, ids) {
+ if (schemaElement.array) {
+ var returnArray = [];
+ for (var j = 0; j < input.length; j++) {
+ returnArray.push(convertListValueToId(input[j], values, ids, schemaElement.name));
+ }
+ return returnArray;
+ } else {
+ return convertListValueToId(input, values, ids, schemaElement.name);
+ }
+ }
+
+ var convertListValueToId = function (value, valuesArray, idsArray, fname) {
+ var textToConvert = _.isObject(value) ? (value.x || value.text) : value;
+ if (textToConvert && textToConvert.match(/^[0-9a-f]{24}$/)) {
+ return textToConvert; // a plugin probably added this
+ } else {
+ var index = valuesArray.indexOf(textToConvert);
+ if (index === -1) {
+ throw new Error('convertListValueToId: Invalid data - value ' + textToConvert + ' not found in ' + valuesArray + ' processing ' + fname);
+ }
+ return idsArray[index];
+ }
+ };
+
+ var preservePristine = function preservePristine(element, fn) {
+ // stop the form being set to dirty when a fn is called
+ // Use when the record (and master) need to be updated by lookup values displayed asynchronously
+ var modelController = element.inheritedData('$ngModelController');
+ var isClean = (modelController && modelController.$pristine);
+ if (isClean) {
+ // fake it to dirty here and reset after call to fn
+ modelController.$pristine = false;
+ }
+ fn();
+ if (isClean) {
+ modelController.$pristine = true;
+ }
+ };
+
+ var convertIdToListValue = function convertIdToListValue(id, idsArray, valuesArray, fname) {
+ if (typeof(id) === 'object') {
+ id = id.id;
+ }
+ var index = idsArray.indexOf(id);
+ if (index === -1) {
+ throw new Error('convertIdToListValue: Invalid data - id ' + id + ' not found in ' + idsArray + ' processing ' + fname);
+ }
+ return valuesArray[index];
+ };
+
+ var processServerData = function processServerData(recordFromServer, $scope, ctrlState) {
+ ctrlState.master = convertToAngularModel($scope.formSchema, recordFromServer, 0, $scope);
+ $scope.phase = 'ready';
+ $scope.cancel();
+ };
+
+ function fillFormFromBackendCustomSchema(schema, $scope:fng.IFormScope, formGeneratorInstance, recordHandlerInstance, ctrlState) {
+ var listOnly = (!$scope.id && !$scope.newRecord);
+ // passing null for formSchema parameter prevents all the work being done when we are just after the list data,
+ // but should be removed when/if formschemas are cached
+ formGeneratorInstance.handleSchema('Main ' + $scope.modelName, schema, listOnly ? null : $scope.formSchema, $scope.listSchema, '', true, $scope, ctrlState);
+
+ if (listOnly) {
+ ctrlState.allowLocationChange = true;
+ } else {
+ var force = true;
+ if (!$scope.newRecord) {
+ $scope.dropConversionWatcher = $scope.$watchCollection('conversions', function (newValue, oldValue) {
+ if (newValue !== oldValue && $scope.originalData) {
+ processServerData($scope.originalData, $scope, ctrlState);
+ }
+ });
+ }
+ $scope.$watch('record', function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (Object.keys(oldValue).length > 0 && $scope.dropConversionWatcher) {
+ $scope.dropConversionWatcher(); // Don't want to convert changed data
+ $scope.dropConversionWatcher = null;
+ }
+ force = formGeneratorInstance.updateDataDependentDisplay(newValue, oldValue, force, $scope);
+ }
+ }, true);
+
+ if ($scope.id) {
+ // Going to read a record
+ if (typeof $scope.dataEventFunctions.onBeforeRead === 'function') {
+ $scope.dataEventFunctions.onBeforeRead($scope.id, function (err) {
+ if (err) {
+ $scope.showError(err);
+ } else {
+ recordHandlerInstance.readRecord($scope, ctrlState);
+ }
+ });
+ } else {
+ recordHandlerInstance.readRecord($scope, ctrlState);
+ }
+ } else {
+ // New record
+ ctrlState.master = {};
+ let passedRecord = $scope.initialiseNewRecord || $location.$$search.r;
+ if (passedRecord) {
+ try {
+ ctrlState.master = JSON.parse(passedRecord);
+
+ // Although this is a new record we are making it dirty from the url so we need to $setDirty
+ $scope.$on('fngCancel', () => {
+ setTimeout(() => {
+ if ($scope[$scope.topLevelFormName]) {
+ $scope[$scope.topLevelFormName].$setDirty();
+ }
+ }, 2); // Has to fire after the setPristime timeout.
+ });
+
+ } catch (e) {
+ console.log('Error parsing specified record : ' + e.message);
+ }
+ }
+ if (typeof $scope.dataEventFunctions.onInitialiseNewRecord === 'function') {
+ $scope.dataEventFunctions.onInitialiseNewRecord(ctrlState.master);
+ }
+ $scope.phase = 'ready';
+ $scope.cancel();
+ }
+ }
+ }
+
+ function handleError($scope: fng.IFormScope) {
+ return function(response:any) : void {
+ if ([200, 400].indexOf(response.status) !== -1) {
+ var errorMessage = '';
+ for (var errorField in response.data.errors) {
+ if (response.data.errors.hasOwnProperty(errorField)) {
+ errorMessage += '
' + $filter('titleCase')(errorField) + ': ';
+ switch (response.data.errors[errorField].type) {
+ case 'enum' :
+ errorMessage += 'You need to select from the list of values';
+ break;
+ default:
+ errorMessage += response.data.errors[errorField].message;
+ break;
+ }
+ errorMessage += '';
+ }
+ }
+ if (errorMessage.length > 0) {
+ errorMessage = response.data.message + '
';
+ } else {
+ errorMessage = response.data.message || 'Error! Sorry - No further details available.';
+ }
+ $scope.showError(errorMessage);
+ } else {
+ $scope.showError(response.status + ' ' + JSON.stringify(response.data));
+ }
+ }
+ }
+
+ function handleIncomingData(data, $scope, ctrlState) {
+ ctrlState.allowLocationChange = false;
+ $scope.phase = 'reading';
+ if (typeof $scope.dataEventFunctions.onAfterRead === 'function') {
+ $scope.dataEventFunctions.onAfterRead(data);
+ }
+ $scope.originalData = data;
+ processServerData(data, $scope, ctrlState);
+ }
+
+ return {
+ readRecord: function readRecord($scope, ctrlState) {
+ // TODO Consider using $parse for this - http://bahmutov.calepin.co/angularjs-parse-hacks.html
+ SubmissionsService.readRecord($scope.modelName, $scope.id)
+ .then(function (response) {
+ let data: any = response.data;
+ if (data.success === false) {
+ $location.path('/404');
+// TODO Figure out tab history updates (check for other tab-history-todos)
+// } else if (response.master) {
+//
+// ctrlState.allowLocationChange = false;
+// $scope.phase = 'ready';
+// $scope.record = angular.copy(response.data);
+// ctrlState.master = angular.copy(response.master);
+// if (response.changed) {
+// $timeout(() => {
+// $scope[$scope.topLevelFormName].$setDirty();
+// });
+// } else {
+// $timeout($scope.setPristine);
+// }
+ } else {
+ handleIncomingData(data, $scope, ctrlState);
+ }
+ }, $scope.handleHttpError);
+ },
+
+ scrollTheList: function scrollTheList($scope) {
+ var pagesLoaded = $scope.pagesLoaded;
+ SubmissionsService.getPagedAndFilteredList($scope.modelName, {
+ aggregate: $location.$$search.a,
+ find: $location.$$search.f,
+ limit: $scope.pageSize,
+ skip: pagesLoaded * $scope.pageSize,
+ order: $location.$$search.o
+ })
+ .then(function (response) {
+ let data: any = response.data;
+ if (angular.isArray(data)) {
+ // I have seen an intermittent problem where a page is requested twice
+ if (pagesLoaded === $scope.pagesLoaded) {
+ $scope.pagesLoaded++;
+ $scope.recordList = $scope.recordList.concat(data);
+ } else {
+ console.log('DEBUG: infinite scroll component asked for a page twice');
+ }
+ } else {
+ $scope.showError(data, 'Invalid query');
+ }
+ }, $scope.handleHttpError);
+ },
+
+ // TODO: Do we need model here? Can we not infer it from scope?
+ deleteRecord: function deleteRecord(model, id, $scope, ctrlState) {
+ SubmissionsService.deleteRecord(model, id)
+ .then(function () {
+ if (typeof $scope.dataEventFunctions.onAfterDelete === 'function') {
+ $scope.dataEventFunctions.onAfterDelete(ctrlState.master);
+ }
+ routingService.redirectTo()('list', $scope, $location);
+ });
+ },
+
+ updateDocument: function updateDocument(dataToSave, options, $scope: fng.IFormScope, ctrlState) {
+ $scope.phase = 'updating';
+
+ SubmissionsService.updateRecord($scope.modelName, $scope.id, dataToSave)
+ .then(function (response) {
+ let data: any = response.data;
+ if (data.success !== false) {
+ if (typeof $scope.dataEventFunctions.onAfterUpdate === 'function') {
+ $scope.dataEventFunctions.onAfterUpdate(data, ctrlState.master);
+ }
+ if (options.redirect) {
+ if (options.allowChange) {
+ ctrlState.allowLocationChange = true;
+ }
+ $window.location = options.redirect;
+ } else {
+ handleIncomingData(data, $scope, ctrlState);
+ $scope.setPristine(false);
+ }
+ } else {
+ $scope.showError(data);
+ }
+ }, $scope.handleHttpError);
+ },
+
+ createNew: function createNew(dataToSave, options, $scope: fng.IFormScope) {
+ SubmissionsService.createRecord($scope.modelName, dataToSave)
+ .then(function (response) {
+ let data: any = response.data;
+ if (data.success !== false) {
+ if (typeof $scope.dataEventFunctions.onAfterCreate === 'function') {
+ $scope.dataEventFunctions.onAfterCreate(data);
+ }
+ if (options.redirect) {
+ $window.location = options.redirect;
+ } else {
+ routingService.redirectTo()('edit', $scope, $location, data._id);
+ }
+ } else {
+ $scope.showError(data);
+ }
+ }, $scope.handleHttpError);
+ },
+
+ getListData: getListData,
+
+ suffixCleanId: suffixCleanId,
+
+ setData: setData,
+
+ setUpSelectOptions: function setUpSelectOptions(lookupCollection, schemaElement, $scope, ctrlState, handleSchema) {
+ var optionsList = $scope[schemaElement.options] = [];
+ var idList = $scope[schemaElement.ids] = [];
+
+ SchemasService.getSchema(lookupCollection)
+ .then(function (response) {
+ let data: any = response.data;
+ var listInstructions = [];
+ handleSchema('Lookup ' + lookupCollection, data, null, listInstructions, '', false, $scope, ctrlState);
+
+ var dataRequest;
+ if (typeof schemaElement.filter !== 'undefined' && schemaElement.filter) {
+ dataRequest = SubmissionsService.getPagedAndFilteredList(lookupCollection, schemaElement.filter);
+ } else {
+ dataRequest = SubmissionsService.getAll(lookupCollection);
+ }
+ dataRequest
+ .then(function (response) {
+ let data: any = response.data;
+ if (data) {
+ for (var i = 0; i < data.length; i++) {
+ var option = '';
+ for (var j = 0; j < listInstructions.length; j++) {
+ let thisVal: string = data[i][listInstructions[j].name];
+ option += thisVal ? thisVal + ' ' : '';
+ }
+ option = option.trim();
+ var pos = _.sortedIndex(optionsList, option);
+ // handle dupes (ideally people will use unique indexes to stop them but...)
+ if (optionsList[pos] === option) {
+ option = option + ' (' + data[i]._id + ')';
+ pos = _.sortedIndex(optionsList, option);
+ }
+ optionsList.splice(pos, 0, option);
+ idList.splice(pos, 0, data[i]._id);
+ }
+ updateRecordWithLookupValues(schemaElement, $scope, ctrlState);
+ }
+ });
+ });
+ },
+
+ preservePristine: preservePristine,
+
+ // Reverse the process of convertToAngularModel
+ convertToMongoModel: function convertToMongoModel(schema, anObject, prefixLength, $scope, schemaName? : string) {
+
+ function convertLookup(lookup, conversionInst) {
+ var retVal;
+ if (conversionInst && conversionInst.fngajax) {
+ if (lookup) {
+ retVal = lookup.id || lookup;
+ }
+ } else if (lookup) {
+ retVal = lookup.text || (lookup.x ? lookup.x.text : lookup);
+ }
+ return retVal;
+ }
+
+ for (var i = 0; i < schema.length; i++) {
+ var fieldname = schema[i].name.slice(prefixLength);
+ var thisField = getListData($scope, anObject, fieldname);
+
+ if (schema[i].schema) {
+ if (thisField) {
+ for (var j = 0; j < thisField.length; j++) {
+ thisField[j] = convertToMongoModel(schema[i].schema, thisField[j], prefixLength + 1 + fieldname.length, $scope, fieldname);
+ }
+ }
+ } else {
+
+ // Convert {array:[{x:'item 1'}]} to {array:['item 1']}
+ if (schema[i].array && simpleArrayNeedsX(schema[i]) && thisField) {
+ for (var k = 0; k < thisField.length; k++) {
+ thisField[k] = thisField[k].x;
+ }
+ }
+
+ // Convert {lookup:'List description for 012abcde'} to {lookup:'012abcde'}
+ var idList = $scope[suffixCleanId(schema[i], '_ids')];
+ let thisConversion: any;
+ if (idList && idList.length > 0) {
+ updateObject(fieldname, anObject, function (value) {
+ return convertToForeignKeys(schema[i], value, $scope[suffixCleanId(schema[i], 'Options')], idList);
+ });
+ } else if (thisConversion = getConversionObject($scope, fieldname, schemaName)) {
+ var lookup = getData(anObject, fieldname, null);
+ var newVal;
+ if (schema[i].array) {
+ newVal = [];
+ if (lookup) {
+ for (var n = 0; n < lookup.length; n++) {
+ newVal[n] = convertLookup(lookup[n], thisConversion);
+ }
+ }
+ } else {
+ newVal = convertLookup(lookup, thisConversion);
+ }
+ setData(anObject, fieldname, null, newVal);
+ }
+
+ }
+ }
+ return anObject;
+ },
+
+ convertIdToListValue: convertIdToListValue,
+
+ handleError: handleError,
+
+ decorateScope: function decorateScope($scope:fng.IFormScope, $uibModal, recordHandlerInstance : fng.IRecordHandler, ctrlState) {
+
+ $scope.handleHttpError = handleError($scope);
+
+ $scope.cancel = function () {
+ angular.copy(ctrlState.master, $scope.record);
+ $scope.$broadcast('fngCancel', $scope);
+ // Let call backs etc resolve in case they dirty form, then clean it
+ $timeout($scope.setPristine);
+ };
+
+ //listener for any child scopes to display messages
+ // pass like this:
+ // scope.$emit('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
+ // or
+ // scope.$broadcast('showErrorMessage', {title: 'Your error Title', body: 'The body of the error message'});
+ $scope.$on('showErrorMessage', function (event, args) {
+ $scope.showError(args.body, args.title);
+ });
+
+ $scope.showError = function (error: any, alertTitle? : string) {
+ $scope.alertTitle = alertTitle ? alertTitle : 'Error!';
+ if (typeof error === 'string') {
+ $scope.errorMessage = error;
+ } else if (error.message && typeof error.message === 'string') {
+ $scope.errorMessage = error.message;
+ } else if (error.data && error.data.message) {
+ $scope.errorMessage = error.data.message;
+ } else {
+ try {
+ $scope.errorMessage = JSON.stringify(error);
+ } catch(e) {
+ $scope.errorMessage = error;
+ }
+ }
+ };
+
+ $scope.dismissError = function () {
+ delete $scope.errorMessage;
+ delete $scope.alertTitle;
+ };
+
+ $scope.prepareForSave = function(cb: (error: string, dataToSave?: any) => void): void {
+ //Convert the lookup values into ids
+ let dataToSave = recordHandlerInstance.convertToMongoModel($scope.formSchema, angular.copy($scope.record), 0, $scope);
+ if ($scope.id) {
+ if (typeof $scope.dataEventFunctions.onBeforeUpdate === 'function') {
+ $scope.dataEventFunctions.onBeforeUpdate(dataToSave, ctrlState.master, function (err) {
+ if (err) {
+ cb(err);
+ } else {
+ cb(null, dataToSave);
+ }
+ });
+ } else {
+ cb(null, dataToSave);
+ }
+ } else {
+ if (typeof $scope.dataEventFunctions.onBeforeCreate === 'function') {
+ $scope.dataEventFunctions.onBeforeCreate(dataToSave, function (err) {
+ if (err) {
+ cb(err);
+ } else {
+ cb(null, dataToSave);
+ }
+ });
+ } else {
+ cb(null, dataToSave);
+ }
+ }
+ };
+
+ $scope.save = function (options) {
+ options = options || {};
+ $scope.prepareForSave((err, dataToSave) => {
+ if (err) {
+ if (err !== '_update_handled_') {
+ $scope.showError(err);
+ }
+ } else if ($scope.id) {
+ recordHandlerInstance.updateDocument(dataToSave, options, $scope, ctrlState);
+ } else {
+ recordHandlerInstance.createNew(dataToSave, options, $scope);
+ }
+ });
+ };
+
+ $scope.newClick = function () {
+ routingService.redirectTo()('new', $scope, $location);
+ };
+
+ $scope.$on('$locationChangeStart', function (event, next) {
+ let changed = !$scope.isCancelDisabled();
+ let curPath = window.location.href.split('/');
+ let nextPath = next.split('/');
+ let tabChangeOnly = true;
+ let i = 0;
+ do {
+ i += 1;
+ if (curPath[i] !== nextPath[i]) {
+ tabChangeOnly = false;
+ }
+ } while (tabChangeOnly && curPath[i] !== 'edit');
+ if (tabChangeOnly) {
+ // let dataToReturn = recordHandlerInstance.convertToMongoModel($scope.formSchema, angular.copy($scope.record), 0, $scope);
+ SubmissionsService.setUpForTabChange($scope.modelName, $scope.id, $scope.record, ctrlState.master, changed);
+ } else if (!ctrlState.allowLocationChange && changed) {
+ event.preventDefault();
+ var modalInstance = $uibModal.open({
+ template: '' +
+ '
' +
+ '
Would you like to save your changes?
' +
+ '
' +
+ '',
+ controller: 'SaveChangesModalCtrl',
+ backdrop: 'static'
+ });
+
+ modalInstance.result.then(
+ function(result) {
+ if (result) {
+ $scope.save({ redirect: next, allowChange: true }); // save changes
+ } else {
+ ctrlState.allowLocationChange = true;
+ $window.location = next;
+ }
+ }
+ );
+ }
+ });
+
+ $scope.deleteClick = function () {
+ if ($scope.record._id) {
+ let confirmDelete: Promise
;
+ if ($scope.unconfirmedDelete) {
+ confirmDelete = Promise.resolve(true);
+ } else {
+ let modalInstance = $uibModal.open({
+ template: '' +
+ '' +
+ '
Are you sure you want to delete this record?
' +
+ '
' +
+ '',
+ controller: 'SaveChangesModalCtrl',
+ backdrop: 'static'
+ });
+ confirmDelete = modalInstance.result;
+ }
+
+ confirmDelete.then(
+ function (result) {
+ if (result) {
+ if (typeof $scope.dataEventFunctions.onBeforeDelete === 'function') {
+ $scope.dataEventFunctions.onBeforeDelete(ctrlState.master, function (err) {
+ if (err) {
+ if (err !== '_delete_handled_') {
+ $scope.showError(err);
+ }
+ } else {
+ recordHandlerInstance.deleteRecord($scope.modelName, $scope.id, $scope, ctrlState);
+ }
+ });
+ } else {
+ recordHandlerInstance.deleteRecord($scope.modelName, $scope.id, $scope, ctrlState);
+ }
+ }
+ }
+ );
+ }
+ };
+
+ $scope.isCancelDisabled = function () {
+ if (typeof $scope.disableFunctions.isCancelDisabled === 'function') {
+ return $scope.disableFunctions.isCancelDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ } else {
+ return $scope[$scope.topLevelFormName] && $scope[$scope.topLevelFormName].$pristine;
+ }
+ };
+
+ $scope.isSaveDisabled = function () {
+ if (typeof $scope.disableFunctions.isSaveDisabled === 'function') {
+ return $scope.disableFunctions.isSaveDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ } else {
+ return ($scope[$scope.topLevelFormName] && ($scope[$scope.topLevelFormName].$invalid || $scope[$scope.topLevelFormName].$pristine));
+ }
+ };
+
+ $scope.isDeleteDisabled = function () {
+ if (typeof $scope.disableFunctions.isDeleteDisabled === 'function') {
+ return $scope.disableFunctions.isDeleteDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ } else {
+ return (!$scope.id);
+ }
+ };
+
+ $scope.isNewDisabled = function () {
+ if (typeof $scope.disableFunctions.isNewDisabled === 'function') {
+ return $scope.disableFunctions.isNewDisabled($scope.record, ctrlState.master, $scope[$scope.topLevelFormName]);
+ } else {
+ return false;
+ }
+ };
+
+ $scope.disabledText = function (localStyling) {
+ var text = '';
+ if ($scope.isSaveDisabled) {
+ text = 'This button is only enabled when the form is complete and valid. Make sure all required inputs are filled in. ' + localStyling;
+ }
+ return text;
+ };
+
+ $scope.getVal = function (expression, index) {
+ if (expression.indexOf('$index') === -1 || typeof index !== 'undefined') {
+ expression = expression.replace(/\$index/g, index);
+ return $scope.$eval('record.' + expression);
+ }
+ //else {
+// Used to show error here, but angular seems to call before record is populated sometimes
+// throw new Error('Invalid expression in getVal(): ' + expression);
+ //}
+ };
+
+ $scope.sortableOptions = {
+ update: function() {
+ if ($scope.topLevelFormName) {
+ $scope[$scope.topLevelFormName].$setDirty();
+ }
+ }
+ };
+
+ },
+
+ fillFormFromBackendCustomSchema: fillFormFromBackendCustomSchema,
+
+ fillFormWithBackendSchema: function fillFormWithBackendSchema($scope, formGeneratorInstance, recordHandlerInstance, ctrlState) {
+
+ SchemasService.getSchema($scope.modelName, $scope.formName)
+ .then(function (response) {
+ let schema: any = response.data;
+ fillFormFromBackendCustomSchema(schema, $scope, formGeneratorInstance, recordHandlerInstance, ctrlState);
+ }, $scope.handleHttpError);
+ }
+ }
+ }
+}
diff --git a/src/client/js/services/schemas.js b/src/client/js/services/schemas.js
new file mode 100644
index 00000000..f820b58b
--- /dev/null
+++ b/src/client/js/services/schemas.js
@@ -0,0 +1,17 @@
+///
+var fng;
+(function (fng) {
+ var services;
+ (function (services) {
+ /*@ngInject*/
+ function SchemasService($http) {
+ return {
+ getSchema: function (modelName, formName) {
+ return $http.get('/api/schema/' + modelName + (formName ? '/' + formName : ''), { cache: true });
+ }
+ };
+ }
+ services.SchemasService = SchemasService;
+ })(services = fng.services || (fng.services = {}));
+})(fng || (fng = {}));
+//# sourceMappingURL=schemas.js.map
\ No newline at end of file
diff --git a/src/client/js/services/schemas.js.map b/src/client/js/services/schemas.js.map
new file mode 100644
index 00000000..2ccb18b4
--- /dev/null
+++ b/src/client/js/services/schemas.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"schemas.js","sourceRoot":"","sources":["schemas.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,IAAO,GAAG,CAUT;AAVD,WAAO,GAAG;IAAC,IAAA,QAAQ,CAUlB;IAVU,WAAA,QAAQ;QAEjB,aAAa;QACb,wBAA+B,KAAK;YAClC,MAAM,CAAC;gBACL,SAAS,EAAE,UAAU,SAAS,EAAE,QAAQ;oBACtC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,GAAG,SAAS,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAC,KAAK,EAAE,IAAI,EAAC,CAAC,CAAC;gBACjG,CAAC;aACF,CAAC;QACJ,CAAC;QANe,uBAAc,iBAM7B,CAAA;IACH,CAAC,EAVU,QAAQ,GAAR,YAAQ,KAAR,YAAQ,QAUlB;AAAD,CAAC,EAVM,GAAG,KAAH,GAAG,QAUT"}
\ No newline at end of file
diff --git a/src/client/js/services/schemas.ts b/src/client/js/services/schemas.ts
new file mode 100644
index 00000000..15ac90c0
--- /dev/null
+++ b/src/client/js/services/schemas.ts
@@ -0,0 +1,13 @@
+///
+
+module fng.services {
+
+ /*@ngInject*/
+ export function SchemasService($http) {
+ return {
+ getSchema: function (modelName, formName) {
+ return $http.get('/api/schema/' + modelName + (formName ? '/' + formName : ''), {cache: true});
+ }
+ };
+ }
+}
diff --git a/src/client/js/services/submissions.js.map b/src/client/js/services/submissions.js.map
new file mode 100644
index 00000000..2f541313
--- /dev/null
+++ b/src/client/js/services/submissions.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"submissions.js","sourceRoot":"","sources":["submissions.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/src/client/js/services/submissions.ts b/src/client/js/services/submissions.ts
new file mode 100644
index 00000000..6b7e8bf9
--- /dev/null
+++ b/src/client/js/services/submissions.ts
@@ -0,0 +1,105 @@
+///
+
+module fng.services {
+
+ /*@ngInject*/
+ export function SubmissionsService($http, $cacheFactory) {
+ /*
+ generate a query string for a filtered and paginated query for submissions.
+ options consists of the following:
+ {
+ aggregate - whether or not to aggregate results (http://docs.mongodb.org/manual/aggregation/)
+ find - find parameter
+ limit - limit results to this number of records
+ skip - skip this number of records before returning results
+ order - sort order
+ }
+ */
+ var generateListQuery = function (options) {
+ var queryString = '';
+
+ var addParameter = function (param, value) {
+ if (value !== undefined && value !== '') {
+ if (typeof value === 'object') {
+ value = JSON.stringify(value);
+ }
+ if (queryString === '') {
+ queryString = '?';
+ } else {
+ queryString += '&';
+ }
+ queryString += param + '=' + value;
+ }
+ };
+
+ addParameter('l', options.limit);
+ addParameter('f', options.find);
+ addParameter('a', options.aggregate);
+ addParameter('o', options.order);
+ addParameter('s', options.skip);
+
+ return queryString;
+ };
+
+// TODO Figure out tab history updates (check for other tab-history-todos)
+//
+// interface ITabChange {
+// model: string;
+// id: string;
+// record: any;
+// master: any;
+// changed: boolean;
+// }
+//
+// let tabChangeData: ITabChange;
+
+ return {
+// TODO Figure out tab history updates (check for other tab-history-todos)
+// setUpForTabChange: function(model: string, id: string, data: any, original: any, changed: boolean) {
+// tabChangeData = {
+// model: model,
+// id: id,
+// record: data,
+// master: original,
+// changed: changed
+// };
+// },
+ getListAttributes: function (ref, id) {
+ return $http.get('/api/' + ref + '/' + id + '/list');
+ },
+ readRecord: function (modelName, id): Promise {
+// TODO Figure out tab history updates (check for other tab-history-todos)
+// let retVal;
+// if (tabChangeData && tabChangeData.model === modelName && tabChangeData.id === id) {
+// retVal = Promise.resolve({data:tabChangeData.record, changed: tabChangeData.changed, master: tabChangeData.master});
+// } else {
+ return $http.get('/api/' + modelName + '/' + id);
+// retVal = $http.get('/api/' + modelName + '/' + id);
+// }
+// tabChangeData = null;
+// return retVal;
+ },
+ getAll: function (modelName, _options) {
+ var options = angular.extend({
+ cache: true
+ }, _options);
+ return $http.get('/api/' + modelName, options);
+ },
+ getPagedAndFilteredList: function (modelName, options) {
+ return $http.get('/api/' + modelName + generateListQuery(options));
+ },
+ deleteRecord: function (model, id) {
+ return $http.delete('/api/' + model + '/' + id);
+ },
+ updateRecord: function (modelName, id, dataToSave) {
+ $cacheFactory.get('$http').remove('/api/' + modelName);
+ return $http.post('/api/' + modelName + '/' + id, dataToSave);
+ },
+ createRecord: function (modelName, dataToSave) {
+ $cacheFactory.get('$http').remove('/api/' + modelName);
+ return $http.post('/api/' + modelName, dataToSave);
+ }
+
+ };
+ }
+}
diff --git a/src/client/less/forms-angular-bs-common.less b/src/client/less/forms-angular-bs-common.less
new file mode 100644
index 00000000..c88affb7
--- /dev/null
+++ b/src/client/less/forms-angular-bs-common.less
@@ -0,0 +1,191 @@
+.list-item {
+ .well;
+}
+
+.list-header, .edit-header {
+ .fixed-header;
+}
+
+.list-body {
+ padding-top: 100px;
+}
+
+.edit-header {
+ padding-top: 10px;
+}
+
+.edit-body {
+ padding-top: 100px;
+}
+
+.page-header {
+ padding-left: 20px;
+ z-index: 102;
+}
+
+.header-rhs {
+ min-width: 226px;
+ min-height: 40px;
+ padding-right: 20px;
+ padding-bottom: 5px;
+ display: block;}
+
+.list-header .header-rhs {
+ margin: 15px 0;
+}
+
+// "Mixins"
+.fixed-header {
+ position: fixed;
+ width: 100%;
+ margin-top: 11px;
+ z-index: 101;
+}
+
+// Modifications to ngGrid style
+
+.gridStyle {
+ border: 1px solid #d4d4d4;
+ margin: auto;
+ height: 400px;
+ .ngTopPanel {
+ background-color: #ffffff;
+ }
+ .ngHeaderCell {
+ background-color: #e4e4e4;
+ }
+ .fng-right {
+ text-align: right;
+ }
+ .fng-left {
+ text-align: left;
+ }
+ .fng-centre, .fng-center {
+ text-align: center;
+ }
+ .ngTotalCell {
+ font-weight: bold;
+ }
+}
+
+button.form-btn {
+ width: 8em;
+ height: 2em;
+}
+
+.form-btn-grp {
+ max-width: 17em;
+}
+
+
+form {
+ &.form-horizontal.compact {
+ input + .help-block, select + .help-block, textarea + .help-block, .uneditable-input + .help-block,
+ .input-prepend + .help-block, .input-append + .help-block {
+ margin-top: 0;
+ margin-bottom: 2px;
+ }
+ hr {
+ margin: 8px 0;
+ }
+ }
+
+ .schema-head {
+ margin-top: 8px;
+ font-weight: bold;
+ }
+ ol.sub-doc {
+ padding: 0;
+ margin: 0;
+ position: relative;
+ li {
+ width: available;
+ display: block;
+ margin: 2px 0;
+ padding-top: 3px;
+ }
+ }
+ .sub-doc-btns {
+ position: absolute;
+ right: 8px;
+ }
+ .schema-foot {
+ margin-top: 0;
+ margin-bottom: 5px;
+ }
+
+ input.ng-invalid:not(.ng-invalid-required):focus {
+ border: solid 1px red;
+ }
+
+ input[type="checkbox"].ng-invalid-required:before, span:first-child input[type="radio"].ng-invalid-required:before {
+ content:"*";
+ font-weight: bold;
+ color: red;
+ margin-left: -8px
+ }
+
+ input.ng-invalid-required, select.fng-invalid-required, select.ng-invalid-required, textarea.ng-invalid-required {
+ background-color: rgba(255, 0, 0, 0.10);
+ }
+
+ option {
+ background-color: white;
+ }
+ .fng-select2 {
+ width: 220px;
+ }
+ .form-inline > .sub-doc {
+ padding: 0 5px;
+ border: none;
+ box-shadow: none;
+ }
+}
+
+a.fng-link, span.fng-link {
+ line-height: 30px;
+}
+
+.form-inline a.fng-link, .form-inline span.fng-link {
+ padding: 0 15px;
+}
+
+// Inline radio buttons need a bigger top margin
+span input[type="radio"] {
+ margin : 9px 0 0;
+}
+
+.global-search {
+ position : relative;
+ float: right;
+}
+
+.results-container {
+ width: 6000px;
+ z-index: 103;
+ position: absolute;
+ top: 41px;
+ right: 0;
+}
+
+.search-results {
+ float: right;
+ border: 1px solid gray;
+ -webkit-box-shadow: 10px 10px 10px #888;
+ box-shadow: 10px 10px 10px #888;
+ background: white;
+ padding: 5px;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+ .search-result.focus {
+ color: white;
+ }
+}
+
+.dropdown-menu > .disabled > li,
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ cursor: not-allowed;
+}
diff --git a/src/client/less/forms-angular-bs2-specific.less b/src/client/less/forms-angular-bs2-specific.less
new file mode 100644
index 00000000..a967da68
--- /dev/null
+++ b/src/client/less/forms-angular-bs2-specific.less
@@ -0,0 +1,93 @@
+@iconSpritePath: "../img/glyphicons-halflings.png";
+@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png";
+
+.list-item {
+ .well-small;
+}
+
+.page-header {
+ font-family: @headingsFontFamily;
+ font-weight: @headingsFontWeight;
+ color: @headingsColor;
+ font-size: @fontSizeLarge;
+ min-height: @navbarHeight;
+}
+
+.fixed-header {
+ background-color: @bodyBackground;
+}
+
+@media (max-width: @navbarCollapseWidth) {
+
+ // UNFIX THE TOPBAR
+ // ----------------
+ // // Remove any padding from the page body
+ .page-body {
+ padding-top: 0;
+ }
+ // Unfix the navbars
+ .page-header {
+ position: static;
+ }
+
+ .global-search {
+ padding-right : 1em;
+ input {
+ width: 12em;
+ }
+ }
+}
+
+form {
+ &.form-horizontal.compact {
+ .control-group {
+ margin-bottom: 2px;
+ }
+ }
+
+ .schema-head {
+ padding: 0 0 0 180px;
+ border-top: 1px solid darken(@wellBackground, 7%);
+ border-bottom: 1px solid darken(@wellBackground, 7%);
+ }
+ .schema-foot {
+ padding: 0 0 0 180px;
+ }
+
+ ol.sub-doc li {
+ border-bottom: 1px solid darken(@wellBackground, 7%);
+ }
+
+ .form-inline > .sub-doc {
+ background-color: @bodyBackground;
+ }
+}
+
+.search-results {
+ .search-result {
+ color: @linkColor;
+ }
+ .search-result.focus {
+ background-color: @linkColorHover;
+ }
+}
+
+// fng-jq-upload overrides for bs2, to make it look the same as bs3
+// TODO: Move these to a BS2 less file in fng-jq-upload and do whatever it takes to make it come out in the appropriate CSS files
+.fileupload-form {
+ position: relative;
+ top: -30px;
+ margin-bottom: -30px;
+}
+
+.fileupload-buttonbar {
+ margin-left: 0;
+}
+
+@media (max-width: 767px) {
+ form {
+ .schema-head, .schema-foot {
+ padding: 5px 15px;
+ }
+ }
+}
diff --git a/src/client/less/forms-angular-bs3-specific.less b/src/client/less/forms-angular-bs3-specific.less
new file mode 100644
index 00000000..07a7071a
--- /dev/null
+++ b/src/client/less/forms-angular-bs3-specific.less
@@ -0,0 +1,160 @@
+// Default styling for the forms-angular classes, to work with navbar-fixed
+.list-item {
+ .well-sm;
+ min-height: 40px;
+}
+
+button.form-btn {
+ font-size: 60%;
+ padding-top: 0.25em;
+}
+
+.form-horizontal {
+ input.input-sm, textarea.input-sm {
+ font-size: 14px;
+ padding: 2px 6px;
+ }
+ select.input-sm {
+ font-size: 14px;
+ padding-left: 5px;
+ }
+ .checkbox {
+ float: left;
+ padding: 5px 10px 0 6px;
+ }
+ .control-label {
+ padding-top: 6px;
+ }
+ .bs3-input {
+ padding-left: 0;
+ }
+ .help-block {
+ clear: left;
+ bottom-margin: 4px;
+ }
+}
+
+// Try and get angular-elastic to work properly (or as near as is really necessary for now)
+// May be worth trying to understand why it works fine in BS2
+textarea[msd-elastic] {
+ min-height: 25px;
+}
+
+.fileupload-buttonbar .btn {
+ padding: 5px 8px;
+}
+
+.page-header {
+ font-family: @headings-font-family;
+ font-weight: @headings-font-weight;
+ color: @headings-color;
+ font-size: @font-size-large;
+ border-bottom: 2px solid @headings-color;
+ min-height: @navbar-height;
+}
+
+.fixed-header {
+ background-color: @body-bg;
+}
+
+@media (max-width: @grid-float-breakpoint) {
+
+ // UNFIX THE TOPBAR
+ // ----------------
+ // // Remove any padding from the page body
+ .page-body {
+ padding-top: 0;
+ }
+
+ // Unfix the navbars
+ .page-header {
+ position: static;
+ }
+
+ .global-search {
+ padding-right: 7px;
+ }
+}
+
+form {
+ &.form-horizontal .form-group {
+ margin-left: 0;
+ margin-right: 0;
+ }
+ &.form-horizontal.compact {
+ .form-group {
+ margin-bottom: 2px;
+ }
+ }
+
+ ol.sub-doc li {
+ border-bottom: 1px solid darken(@well-bg, 7%);
+ }
+
+ .schema-head, .schema-foot {
+ border-top: 1px solid darken(@well-bg, 7%);
+ border-bottom: 1px solid darken(@well-bg, 7%);
+ padding-left: 23px;
+ }
+
+ // .radio input[type="radio"], .radio-inline input[type="radio"], .checkbox-inline input[type="checkbox"]
+ .checkbox input[type="checkbox"] {
+ margin-left: -5px;
+ }
+
+ .form-inline > .sub-doc {
+ background-color: @body-bg;
+ }
+}
+
+.search-results {
+ .search-result {
+ color: @link-color;
+ }
+ .search-result.focus {
+ background-color: @link-hover-color;
+ }
+}
+
+.form-inline {
+ .row {
+ margin-left: 5px;
+ margin-right: 0;
+ }
+ .form-group .input-group {
+ display: table-cell;
+ .input-group-addon {
+ display: none;
+ }
+ }
+}
+
+form {
+ .tab-content {
+ margin-top: 5px;
+ }
+}
+
+@media (max-width: 767px) {
+ // For some reason bootstrap only does this for large windows - need it for search on mobile
+ .navbar-form {
+ width: auto;
+ border: 0;
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+
+ .navbar-form.navbar-right:last-child {
+ margin-right: -15px;
+ }
+
+ form {
+ .schema-head, .schema-foot {
+ padding: 5px 15px;
+ }
+ }
+
+}
diff --git a/app/css/forms-angular.css b/src/client/less/forms-angular-with-bs2.css
similarity index 68%
rename from app/css/forms-angular.css
rename to src/client/less/forms-angular-with-bs2.css
index 68fb67ba..d22d6771 100644
--- a/app/css/forms-angular.css
+++ b/src/client/less/forms-angular-with-bs2.css
@@ -1,18 +1,24 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2013 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat.
+ */
.clearfix {
*zoom: 1;
}
-
.clearfix:before,
.clearfix:after {
display: table;
- line-height: 0;
content: "";
+ line-height: 0;
}
-
.clearfix:after {
clear: both;
}
-
.hide-text {
font: 0/0 a;
color: transparent;
@@ -20,16 +26,14 @@
background-color: transparent;
border: 0;
}
-
.input-block-level {
display: block;
width: 100%;
min-height: 30px;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
-
article,
aside,
details,
@@ -42,7 +46,6 @@ nav,
section {
display: block;
}
-
audio,
canvas,
video {
@@ -50,28 +53,23 @@ video {
*display: inline;
*zoom: 1;
}
-
audio:not([controls]) {
display: none;
}
-
html {
font-size: 100%;
-webkit-text-size-adjust: 100%;
- -ms-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
}
-
a:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
-
a:hover,
a:active {
outline: 0;
}
-
sub,
sup {
position: relative;
@@ -79,29 +77,28 @@ sup {
line-height: 0;
vertical-align: baseline;
}
-
sup {
top: -0.5em;
}
-
sub {
bottom: -0.25em;
}
-
img {
+ /* Responsive images (ensure images don't scale beyond their parents) */
+ max-width: 100%;
+ /* Part 1: Set a maxium relative to the parent */
width: auto\9;
+ /* IE7-8 need help adjusting responsive images */
height: auto;
- max-width: 100%;
+ /* Part 2: Scale the height according to the width, otherwise you get stretching */
vertical-align: middle;
border: 0;
-ms-interpolation-mode: bicubic;
}
-
#map_canvas img,
.google-maps img {
max-width: none;
}
-
button,
input,
select,
@@ -110,27 +107,23 @@ textarea {
font-size: 100%;
vertical-align: middle;
}
-
button,
input {
*overflow: visible;
line-height: normal;
}
-
button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}
-
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
- cursor: pointer;
-webkit-appearance: button;
+ cursor: pointer;
}
-
label,
select,
button,
@@ -141,28 +134,24 @@ input[type="radio"],
input[type="checkbox"] {
cursor: pointer;
}
-
input[type="search"] {
-webkit-box-sizing: content-box;
- -moz-box-sizing: content-box;
- box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
-webkit-appearance: textfield;
}
-
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
}
-
textarea {
overflow: auto;
vertical-align: top;
}
-
@media print {
* {
- color: #000 !important;
text-shadow: none !important;
+ color: #000 !important;
background: transparent !important;
box-shadow: none !important;
}
@@ -196,7 +185,7 @@ textarea {
img {
max-width: 100% !important;
}
- @page {
+ @page {
margin: 0.5cm;
}
p,
@@ -210,7 +199,6 @@ textarea {
page-break-after: avoid;
}
}
-
body {
margin: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
@@ -219,938 +207,405 @@ body {
color: #333333;
background-color: #ffffff;
}
-
a {
color: #0088cc;
text-decoration: none;
}
-
a:hover,
a:focus {
color: #005580;
text-decoration: underline;
}
-
.img-rounded {
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
}
-
.img-polaroid {
padding: 4px;
background-color: #fff;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
-
.img-circle {
-webkit-border-radius: 500px;
- -moz-border-radius: 500px;
- border-radius: 500px;
-}
-
-.row {
- margin-left: -20px;
- *zoom: 1;
-}
-
-.row:before,
-.row:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.row:after {
- clear: both;
-}
-
-.row:before,
-.row:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.row:after {
- clear: both;
-}
-
-[class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 20px;
-}
-
-.container,
-.navbar-static-top .container,
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
- width: 940px;
-}
-
-.span12 {
- width: 940px;
-}
-
-.span11 {
- width: 860px;
-}
-
-.span10 {
- width: 780px;
-}
-
-.span9 {
- width: 700px;
-}
-
-.span8 {
- width: 620px;
+ -moz-border-radius: 500px;
+ border-radius: 500px;
}
-
-.span7 {
- width: 540px;
-}
-
-.span6 {
- width: 460px;
-}
-
-.span5 {
- width: 380px;
-}
-
-.span4 {
- width: 300px;
-}
-
-.span3 {
- width: 220px;
-}
-
-.span2 {
- width: 140px;
-}
-
-.span1 {
- width: 60px;
-}
-
-.offset12 {
- margin-left: 980px;
-}
-
-.offset11 {
- margin-left: 900px;
-}
-
-.offset10 {
- margin-left: 820px;
-}
-
-.offset9 {
- margin-left: 740px;
-}
-
-.offset8 {
- margin-left: 660px;
-}
-
-.offset7 {
- margin-left: 580px;
-}
-
-.offset6 {
- margin-left: 500px;
-}
-
-.offset5 {
- margin-left: 420px;
-}
-
-.offset4 {
- margin-left: 340px;
-}
-
-.offset3 {
- margin-left: 260px;
-}
-
-.offset2 {
- margin-left: 180px;
-}
-
-.offset1 {
- margin-left: 100px;
-}
-
.row {
margin-left: -20px;
*zoom: 1;
}
-
.row:before,
.row:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.row:after {
- clear: both;
-}
-
-.row:before,
-.row:after {
- display: table;
line-height: 0;
- content: "";
}
-
.row:after {
clear: both;
}
-
[class*="span"] {
float: left;
min-height: 1px;
margin-left: 20px;
}
-
.container,
.navbar-static-top .container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 940px;
}
-
.span12 {
width: 940px;
}
-
.span11 {
width: 860px;
}
-
.span10 {
width: 780px;
}
-
.span9 {
width: 700px;
}
-
.span8 {
width: 620px;
}
-
.span7 {
width: 540px;
}
-
.span6 {
width: 460px;
}
-
.span5 {
width: 380px;
}
-
.span4 {
width: 300px;
}
-
.span3 {
width: 220px;
}
-
.span2 {
width: 140px;
}
-
.span1 {
width: 60px;
}
-
.offset12 {
margin-left: 980px;
}
-
.offset11 {
margin-left: 900px;
}
-
.offset10 {
margin-left: 820px;
}
-
.offset9 {
margin-left: 740px;
}
-
.offset8 {
margin-left: 660px;
}
-
.offset7 {
margin-left: 580px;
}
-
.offset6 {
margin-left: 500px;
}
-
.offset5 {
margin-left: 420px;
}
-
.offset4 {
margin-left: 340px;
}
-
.offset3 {
margin-left: 260px;
}
-
.offset2 {
margin-left: 180px;
}
-
.offset1 {
margin-left: 100px;
}
-
.row-fluid {
width: 100%;
*zoom: 1;
}
-
.row-fluid:before,
.row-fluid:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.row-fluid:after {
- clear: both;
-}
-
-.row-fluid:before,
-.row-fluid:after {
- display: table;
line-height: 0;
- content: "";
}
-
.row-fluid:after {
clear: both;
}
-
.row-fluid [class*="span"] {
display: block;
- float: left;
width: 100%;
min-height: 30px;
- margin-left: 2.127659574468085%;
- *margin-left: 2.074468085106383%;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ float: left;
+ margin-left: 2.12765957%;
+ *margin-left: 2.07446809%;
}
-
.row-fluid [class*="span"]:first-child {
margin-left: 0;
}
-
.row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.127659574468085%;
+ margin-left: 2.12765957%;
}
-
.row-fluid .span12 {
width: 100%;
- *width: 99.94680851063829%;
+ *width: 99.94680851%;
}
-
.row-fluid .span11 {
- width: 91.48936170212765%;
- *width: 91.43617021276594%;
+ width: 91.4893617%;
+ *width: 91.43617021%;
}
-
.row-fluid .span10 {
- width: 82.97872340425532%;
- *width: 82.92553191489361%;
+ width: 82.9787234%;
+ *width: 82.92553191%;
}
-
.row-fluid .span9 {
- width: 74.46808510638297%;
- *width: 74.41489361702126%;
+ width: 74.46808511%;
+ *width: 74.41489362%;
}
-
.row-fluid .span8 {
- width: 65.95744680851064%;
- *width: 65.90425531914893%;
+ width: 65.95744681%;
+ *width: 65.90425532%;
}
-
.row-fluid .span7 {
- width: 57.44680851063829%;
- *width: 57.39361702127659%;
+ width: 57.44680851%;
+ *width: 57.39361702%;
}
-
.row-fluid .span6 {
- width: 48.93617021276595%;
- *width: 48.88297872340425%;
+ width: 48.93617021%;
+ *width: 48.88297872%;
}
-
.row-fluid .span5 {
- width: 40.42553191489362%;
- *width: 40.37234042553192%;
+ width: 40.42553191%;
+ *width: 40.37234043%;
}
-
.row-fluid .span4 {
- width: 31.914893617021278%;
- *width: 31.861702127659576%;
+ width: 31.91489362%;
+ *width: 31.86170213%;
}
-
.row-fluid .span3 {
- width: 23.404255319148934%;
- *width: 23.351063829787233%;
+ width: 23.40425532%;
+ *width: 23.35106383%;
}
-
.row-fluid .span2 {
- width: 14.893617021276595%;
- *width: 14.840425531914894%;
+ width: 14.89361702%;
+ *width: 14.84042553%;
}
-
.row-fluid .span1 {
- width: 6.382978723404255%;
- *width: 6.329787234042553%;
+ width: 6.38297872%;
+ *width: 6.32978723%;
}
-
.row-fluid .offset12 {
- margin-left: 104.25531914893617%;
- *margin-left: 104.14893617021275%;
+ margin-left: 104.25531915%;
+ *margin-left: 104.14893617%;
}
-
.row-fluid .offset12:first-child {
- margin-left: 102.12765957446808%;
- *margin-left: 102.02127659574467%;
+ margin-left: 102.12765957%;
+ *margin-left: 102.0212766%;
}
-
.row-fluid .offset11 {
- margin-left: 95.74468085106382%;
- *margin-left: 95.6382978723404%;
+ margin-left: 95.74468085%;
+ *margin-left: 95.63829787%;
}
-
.row-fluid .offset11:first-child {
- margin-left: 93.61702127659574%;
- *margin-left: 93.51063829787232%;
+ margin-left: 93.61702128%;
+ *margin-left: 93.5106383%;
}
-
.row-fluid .offset10 {
- margin-left: 87.23404255319149%;
- *margin-left: 87.12765957446807%;
+ margin-left: 87.23404255%;
+ *margin-left: 87.12765957%;
}
-
.row-fluid .offset10:first-child {
- margin-left: 85.1063829787234%;
- *margin-left: 84.99999999999999%;
+ margin-left: 85.10638298%;
+ *margin-left: 85%;
}
-
.row-fluid .offset9 {
- margin-left: 78.72340425531914%;
- *margin-left: 78.61702127659572%;
+ margin-left: 78.72340426%;
+ *margin-left: 78.61702128%;
}
-
.row-fluid .offset9:first-child {
- margin-left: 76.59574468085106%;
- *margin-left: 76.48936170212764%;
+ margin-left: 76.59574468%;
+ *margin-left: 76.4893617%;
}
-
.row-fluid .offset8 {
- margin-left: 70.2127659574468%;
- *margin-left: 70.10638297872339%;
+ margin-left: 70.21276596%;
+ *margin-left: 70.10638298%;
}
-
.row-fluid .offset8:first-child {
- margin-left: 68.08510638297872%;
- *margin-left: 67.9787234042553%;
+ margin-left: 68.08510638%;
+ *margin-left: 67.9787234%;
}
-
.row-fluid .offset7 {
- margin-left: 61.70212765957446%;
- *margin-left: 61.59574468085106%;
+ margin-left: 61.70212766%;
+ *margin-left: 61.59574468%;
}
-
.row-fluid .offset7:first-child {
- margin-left: 59.574468085106375%;
- *margin-left: 59.46808510638297%;
+ margin-left: 59.57446809%;
+ *margin-left: 59.46808511%;
}
-
.row-fluid .offset6 {
- margin-left: 53.191489361702125%;
- *margin-left: 53.085106382978715%;
+ margin-left: 53.19148936%;
+ *margin-left: 53.08510638%;
}
-
.row-fluid .offset6:first-child {
- margin-left: 51.063829787234035%;
- *margin-left: 50.95744680851063%;
+ margin-left: 51.06382979%;
+ *margin-left: 50.95744681%;
}
-
.row-fluid .offset5 {
- margin-left: 44.68085106382979%;
- *margin-left: 44.57446808510638%;
+ margin-left: 44.68085106%;
+ *margin-left: 44.57446809%;
}
-
.row-fluid .offset5:first-child {
- margin-left: 42.5531914893617%;
- *margin-left: 42.4468085106383%;
+ margin-left: 42.55319149%;
+ *margin-left: 42.44680851%;
}
-
.row-fluid .offset4 {
- margin-left: 36.170212765957444%;
- *margin-left: 36.06382978723405%;
+ margin-left: 36.17021277%;
+ *margin-left: 36.06382979%;
}
-
.row-fluid .offset4:first-child {
- margin-left: 34.04255319148936%;
- *margin-left: 33.93617021276596%;
+ margin-left: 34.04255319%;
+ *margin-left: 33.93617021%;
}
-
.row-fluid .offset3 {
- margin-left: 27.659574468085104%;
- *margin-left: 27.5531914893617%;
+ margin-left: 27.65957447%;
+ *margin-left: 27.55319149%;
}
-
.row-fluid .offset3:first-child {
- margin-left: 25.53191489361702%;
- *margin-left: 25.425531914893618%;
+ margin-left: 25.53191489%;
+ *margin-left: 25.42553191%;
}
-
.row-fluid .offset2 {
- margin-left: 19.148936170212764%;
- *margin-left: 19.04255319148936%;
+ margin-left: 19.14893617%;
+ *margin-left: 19.04255319%;
}
-
.row-fluid .offset2:first-child {
- margin-left: 17.02127659574468%;
- *margin-left: 16.914893617021278%;
+ margin-left: 17.0212766%;
+ *margin-left: 16.91489362%;
}
-
.row-fluid .offset1 {
- margin-left: 10.638297872340425%;
- *margin-left: 10.53191489361702%;
+ margin-left: 10.63829787%;
+ *margin-left: 10.53191489%;
}
-
.row-fluid .offset1:first-child {
- margin-left: 8.51063829787234%;
- *margin-left: 8.404255319148938%;
+ margin-left: 8.5106383%;
+ *margin-left: 8.40425532%;
}
-
-.row-fluid {
- width: 100%;
+[class*="span"].hide,
+.row-fluid [class*="span"].hide {
+ display: none;
+}
+[class*="span"].pull-right,
+.row-fluid [class*="span"].pull-right {
+ float: right;
+}
+.container {
+ margin-right: auto;
+ margin-left: auto;
*zoom: 1;
}
-
-.row-fluid:before,
-.row-fluid:after {
+.container:before,
+.container:after {
display: table;
- line-height: 0;
content: "";
+ line-height: 0;
}
-
-.row-fluid:after {
+.container:after {
clear: both;
}
-
-.row-fluid:before,
-.row-fluid:after {
+.container-fluid {
+ padding-right: 20px;
+ padding-left: 20px;
+ *zoom: 1;
+}
+.container-fluid:before,
+.container-fluid:after {
display: table;
- line-height: 0;
content: "";
+ line-height: 0;
}
-
-.row-fluid:after {
+.container-fluid:after {
clear: both;
}
-
-.row-fluid [class*="span"] {
- display: block;
- float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.127659574468085%;
- *margin-left: 2.074468085106383%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.row-fluid [class*="span"]:first-child {
- margin-left: 0;
-}
-
-.row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.127659574468085%;
-}
-
-.row-fluid .span12 {
- width: 100%;
- *width: 99.94680851063829%;
-}
-
-.row-fluid .span11 {
- width: 91.48936170212765%;
- *width: 91.43617021276594%;
+p {
+ margin: 0 0 10px;
}
-
-.row-fluid .span10 {
- width: 82.97872340425532%;
- *width: 82.92553191489361%;
+.lead {
+ margin-bottom: 20px;
+ font-size: 21px;
+ font-weight: 200;
+ line-height: 30px;
}
-
-.row-fluid .span9 {
- width: 74.46808510638297%;
- *width: 74.41489361702126%;
+small {
+ font-size: 85%;
}
-
-.row-fluid .span8 {
- width: 65.95744680851064%;
- *width: 65.90425531914893%;
+strong {
+ font-weight: bold;
}
-
-.row-fluid .span7 {
- width: 57.44680851063829%;
- *width: 57.39361702127659%;
+em {
+ font-style: italic;
}
-
-.row-fluid .span6 {
- width: 48.93617021276595%;
- *width: 48.88297872340425%;
+cite {
+ font-style: normal;
}
-
-.row-fluid .span5 {
- width: 40.42553191489362%;
- *width: 40.37234042553192%;
+.muted {
+ color: #999999;
}
-
-.row-fluid .span4 {
- width: 31.914893617021278%;
- *width: 31.861702127659576%;
+a.muted:hover,
+a.muted:focus {
+ color: #808080;
}
-
-.row-fluid .span3 {
- width: 23.404255319148934%;
- *width: 23.351063829787233%;
+.text-warning {
+ color: #c09853;
}
-
-.row-fluid .span2 {
- width: 14.893617021276595%;
- *width: 14.840425531914894%;
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #a47e3c;
}
-
-.row-fluid .span1 {
- width: 6.382978723404255%;
- *width: 6.329787234042553%;
+.text-error {
+ color: #b94a48;
}
-
-.row-fluid .offset12 {
- margin-left: 104.25531914893617%;
- *margin-left: 104.14893617021275%;
+a.text-error:hover,
+a.text-error:focus {
+ color: #953b39;
}
-
-.row-fluid .offset12:first-child {
- margin-left: 102.12765957446808%;
- *margin-left: 102.02127659574467%;
+.text-info {
+ color: #3a87ad;
}
-
-.row-fluid .offset11 {
- margin-left: 95.74468085106382%;
- *margin-left: 95.6382978723404%;
+a.text-info:hover,
+a.text-info:focus {
+ color: #2d6987;
}
-
-.row-fluid .offset11:first-child {
- margin-left: 93.61702127659574%;
- *margin-left: 93.51063829787232%;
+.text-success {
+ color: #468847;
}
-
-.row-fluid .offset10 {
- margin-left: 87.23404255319149%;
- *margin-left: 87.12765957446807%;
+a.text-success:hover,
+a.text-success:focus {
+ color: #356635;
}
-
-.row-fluid .offset10:first-child {
- margin-left: 85.1063829787234%;
- *margin-left: 84.99999999999999%;
+.text-left {
+ text-align: left;
}
-
-.row-fluid .offset9 {
- margin-left: 78.72340425531914%;
- *margin-left: 78.61702127659572%;
+.text-right {
+ text-align: right;
}
-
-.row-fluid .offset9:first-child {
- margin-left: 76.59574468085106%;
- *margin-left: 76.48936170212764%;
+.text-center {
+ text-align: center;
}
-
-.row-fluid .offset8 {
- margin-left: 70.2127659574468%;
- *margin-left: 70.10638297872339%;
-}
-
-.row-fluid .offset8:first-child {
- margin-left: 68.08510638297872%;
- *margin-left: 67.9787234042553%;
-}
-
-.row-fluid .offset7 {
- margin-left: 61.70212765957446%;
- *margin-left: 61.59574468085106%;
-}
-
-.row-fluid .offset7:first-child {
- margin-left: 59.574468085106375%;
- *margin-left: 59.46808510638297%;
-}
-
-.row-fluid .offset6 {
- margin-left: 53.191489361702125%;
- *margin-left: 53.085106382978715%;
-}
-
-.row-fluid .offset6:first-child {
- margin-left: 51.063829787234035%;
- *margin-left: 50.95744680851063%;
-}
-
-.row-fluid .offset5 {
- margin-left: 44.68085106382979%;
- *margin-left: 44.57446808510638%;
-}
-
-.row-fluid .offset5:first-child {
- margin-left: 42.5531914893617%;
- *margin-left: 42.4468085106383%;
-}
-
-.row-fluid .offset4 {
- margin-left: 36.170212765957444%;
- *margin-left: 36.06382978723405%;
-}
-
-.row-fluid .offset4:first-child {
- margin-left: 34.04255319148936%;
- *margin-left: 33.93617021276596%;
-}
-
-.row-fluid .offset3 {
- margin-left: 27.659574468085104%;
- *margin-left: 27.5531914893617%;
-}
-
-.row-fluid .offset3:first-child {
- margin-left: 25.53191489361702%;
- *margin-left: 25.425531914893618%;
-}
-
-.row-fluid .offset2 {
- margin-left: 19.148936170212764%;
- *margin-left: 19.04255319148936%;
-}
-
-.row-fluid .offset2:first-child {
- margin-left: 17.02127659574468%;
- *margin-left: 16.914893617021278%;
-}
-
-.row-fluid .offset1 {
- margin-left: 10.638297872340425%;
- *margin-left: 10.53191489361702%;
-}
-
-.row-fluid .offset1:first-child {
- margin-left: 8.51063829787234%;
- *margin-left: 8.404255319148938%;
-}
-
-[class*="span"].hide,
-.row-fluid [class*="span"].hide {
- display: none;
-}
-
-[class*="span"].pull-right,
-.row-fluid [class*="span"].pull-right {
- float: right;
-}
-
-.container {
- margin-right: auto;
- margin-left: auto;
- *zoom: 1;
-}
-
-.container:before,
-.container:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container:after {
- clear: both;
-}
-
-.container:before,
-.container:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container:after {
- clear: both;
-}
-
-.container:before,
-.container:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container:after {
- clear: both;
-}
-
-.container:before,
-.container:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container:after {
- clear: both;
-}
-
-.container-fluid {
- padding-right: 20px;
- padding-left: 20px;
- *zoom: 1;
-}
-
-.container-fluid:before,
-.container-fluid:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container-fluid:after {
- clear: both;
-}
-
-.container-fluid:before,
-.container-fluid:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.container-fluid:after {
- clear: both;
-}
-
-p {
- margin: 0 0 10px;
-}
-
-.lead {
- margin-bottom: 20px;
- font-size: 21px;
- font-weight: 200;
- line-height: 30px;
-}
-
-small {
- font-size: 85%;
-}
-
-strong {
- font-weight: bold;
-}
-
-em {
- font-style: italic;
-}
-
-cite {
- font-style: normal;
-}
-
-.muted {
- color: #999999;
-}
-
-a.muted:hover,
-a.muted:focus {
- color: #808080;
-}
-
-.text-warning {
- color: #c09853;
-}
-
-a.text-warning:hover,
-a.text-warning:focus {
- color: #a47e3c;
-}
-
-.text-error {
- color: #b94a48;
-}
-
-a.text-error:hover,
-a.text-error:focus {
- color: #953b39;
-}
-
-.text-info {
- color: #3a87ad;
-}
-
-a.text-info:hover,
-a.text-info:focus {
- color: #2d6987;
-}
-
-.text-success {
- color: #468847;
-}
-
-a.text-success:hover,
-a.text-success:focus {
- color: #356635;
-}
-
-.text-left {
- text-align: left;
-}
-
-.text-right {
- text-align: right;
-}
-
-.text-center {
- text-align: center;
-}
-
h1,
h2,
h3,
@@ -1164,7 +619,6 @@ h6 {
color: inherit;
text-rendering: optimizelegibility;
}
-
h1 small,
h2 small,
h3 small,
@@ -1175,195 +629,150 @@ h6 small {
line-height: 1;
color: #999999;
}
-
h1,
h2,
h3 {
line-height: 40px;
}
-
h1 {
font-size: 38.5px;
}
-
h2 {
font-size: 31.5px;
}
-
h3 {
font-size: 24.5px;
}
-
h4 {
font-size: 17.5px;
}
-
h5 {
font-size: 14px;
}
-
h6 {
font-size: 11.9px;
}
-
h1 small {
font-size: 24.5px;
}
-
h2 small {
font-size: 17.5px;
}
-
h3 small {
font-size: 14px;
}
-
h4 small {
font-size: 14px;
}
-
.page-header {
padding-bottom: 9px;
margin: 20px 0 30px;
border-bottom: 1px solid #eeeeee;
}
-
ul,
ol {
padding: 0;
margin: 0 0 10px 25px;
}
-
ul ul,
ul ol,
ol ol,
ol ul {
margin-bottom: 0;
}
-
li {
line-height: 20px;
}
-
ul.unstyled,
ol.unstyled {
margin-left: 0;
list-style: none;
}
-
ul.inline,
ol.inline {
margin-left: 0;
list-style: none;
}
-
ul.inline > li,
ol.inline > li {
display: inline-block;
*display: inline;
- padding-right: 5px;
- padding-left: 5px;
+ /* IE7 inline-block hack */
*zoom: 1;
+ padding-left: 5px;
+ padding-right: 5px;
}
-
dl {
margin-bottom: 20px;
}
-
dt,
dd {
line-height: 20px;
}
-
dt {
font-weight: bold;
}
-
dd {
margin-left: 10px;
}
-
.dl-horizontal {
*zoom: 1;
}
-
.dl-horizontal:before,
.dl-horizontal:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.dl-horizontal:after {
- clear: both;
-}
-
-.dl-horizontal:before,
-.dl-horizontal:after {
- display: table;
line-height: 0;
- content: "";
}
-
.dl-horizontal:after {
clear: both;
}
-
.dl-horizontal dt {
float: left;
width: 160px;
- overflow: hidden;
clear: left;
text-align: right;
+ overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
-
.dl-horizontal dd {
margin-left: 180px;
}
-
hr {
margin: 20px 0;
border: 0;
border-top: 1px solid #eeeeee;
border-bottom: 1px solid #ffffff;
}
-
abbr[title],
abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted #999999;
}
-
abbr.initialism {
font-size: 90%;
text-transform: uppercase;
}
-
blockquote {
padding: 0 0 0 15px;
margin: 0 0 20px;
border-left: 5px solid #eeeeee;
}
-
blockquote p {
margin-bottom: 0;
font-size: 17.5px;
font-weight: 300;
line-height: 1.25;
}
-
blockquote small {
display: block;
line-height: 20px;
color: #999999;
}
-
blockquote small:before {
content: '\2014 \00A0';
}
-
blockquote.pull-right {
float: right;
padding-right: 15px;
@@ -1371,34 +780,28 @@ blockquote.pull-right {
border-right: 5px solid #eeeeee;
border-left: 0;
}
-
blockquote.pull-right p,
blockquote.pull-right small {
text-align: right;
}
-
blockquote.pull-right small:before {
content: '';
}
-
blockquote.pull-right small:after {
content: '\00A0 \2014';
}
-
q:before,
q:after,
blockquote:before,
blockquote:after {
content: "";
}
-
address {
display: block;
margin-bottom: 20px;
font-style: normal;
line-height: 20px;
}
-
code,
pre {
padding: 0 3px 2px;
@@ -1406,18 +809,16 @@ pre {
font-size: 12px;
color: #333333;
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
-
code {
padding: 2px 4px;
color: #d14;
- white-space: nowrap;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
+ white-space: nowrap;
}
-
pre {
display: block;
padding: 9.5px;
@@ -1432,14 +833,12 @@ pre {
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.15);
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
pre.prettyprint {
margin-bottom: 20px;
}
-
pre code {
padding: 0;
color: inherit;
@@ -1448,22 +847,18 @@ pre code {
background-color: transparent;
border: 0;
}
-
.pre-scrollable {
max-height: 340px;
overflow-y: scroll;
}
-
form {
margin: 0 0 20px;
}
-
fieldset {
padding: 0;
margin: 0;
border: 0;
}
-
legend {
display: block;
width: 100%;
@@ -1475,12 +870,10 @@ legend {
border: 0;
border-bottom: 1px solid #e5e5e5;
}
-
legend small {
font-size: 15px;
color: #999999;
}
-
label,
input,
button,
@@ -1490,19 +883,16 @@ textarea {
font-weight: normal;
line-height: 20px;
}
-
input,
button,
select,
textarea {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
-
label {
display: block;
margin-bottom: 5px;
}
-
select,
textarea,
input[type="text"],
@@ -1527,22 +917,19 @@ input[type="color"],
font-size: 14px;
line-height: 20px;
color: #555555;
- vertical-align: middle;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ vertical-align: middle;
}
-
input,
textarea,
.uneditable-input {
width: 206px;
}
-
textarea {
height: auto;
}
-
textarea,
input[type="text"],
input[type="password"],
@@ -1562,14 +949,13 @@ input[type="color"],
background-color: #ffffff;
border: 1px solid #cccccc;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
- -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
- -o-transition: border linear 0.2s, box-shadow linear 0.2s;
- transition: border linear 0.2s, box-shadow linear 0.2s;
-}
-
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -webkit-transition: border linear .2s, box-shadow linear .2s;
+ -moz-transition: border linear .2s, box-shadow linear .2s;
+ -o-transition: border linear .2s, box-shadow linear .2s;
+ transition: border linear .2s, box-shadow linear .2s;
+}
textarea:focus,
input[type="text"]:focus,
input[type="password"]:focus,
@@ -1590,20 +976,19 @@ input[type="color"]:focus,
outline: 0;
outline: thin dotted \9;
/* IE6-9 */
-
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
}
-
input[type="radio"],
input[type="checkbox"] {
margin: 4px 0 0;
- margin-top: 1px \9;
*margin-top: 0;
+ /* IE7 */
+ margin-top: 1px \9;
+ /* IE8-9 */
line-height: normal;
}
-
input[type="file"],
input[type="image"],
input[type="submit"],
@@ -1613,29 +998,23 @@ input[type="radio"],
input[type="checkbox"] {
width: auto;
}
-
select,
input[type="file"] {
height: 30px;
/* In IE7, the height of the select element cannot be changed by height, only font-size */
-
*margin-top: 4px;
/* For IE7, add top margin to align select with labels */
-
line-height: 30px;
}
-
select {
width: 220px;
- background-color: #ffffff;
border: 1px solid #cccccc;
+ background-color: #ffffff;
}
-
select[multiple],
select[size] {
height: auto;
}
-
select:focus,
input[type="file"]:focus,
input[type="radio"]:focus,
@@ -1644,75 +1023,50 @@ input[type="checkbox"]:focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
-
.uneditable-input,
.uneditable-textarea {
color: #999999;
- cursor: not-allowed;
background-color: #fcfcfc;
border-color: #cccccc;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+ cursor: not-allowed;
}
-
.uneditable-input {
overflow: hidden;
white-space: nowrap;
}
-
.uneditable-textarea {
width: auto;
height: auto;
}
-
-input:-moz-placeholder,
-textarea:-moz-placeholder {
- color: #999999;
-}
-
-input:-ms-input-placeholder,
-textarea:-ms-input-placeholder {
- color: #999999;
-}
-
-input::-webkit-input-placeholder,
-textarea::-webkit-input-placeholder {
- color: #999999;
-}
-
input:-moz-placeholder,
textarea:-moz-placeholder {
color: #999999;
}
-
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
color: #999999;
}
-
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
color: #999999;
}
-
.radio,
.checkbox {
min-height: 20px;
padding-left: 20px;
}
-
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
float: left;
margin-left: -20px;
}
-
.controls > .radio:first-child,
.controls > .checkbox:first-child {
padding-top: 5px;
}
-
.radio.inline,
.checkbox.inline {
display: inline-block;
@@ -1720,36 +1074,28 @@ textarea::-webkit-input-placeholder {
margin-bottom: 0;
vertical-align: middle;
}
-
.radio.inline + .radio.inline,
.checkbox.inline + .checkbox.inline {
margin-left: 10px;
}
-
.input-mini {
width: 60px;
}
-
.input-small {
width: 90px;
}
-
.input-medium {
width: 150px;
}
-
.input-large {
width: 210px;
}
-
.input-xlarge {
width: 270px;
}
-
.input-xxlarge {
width: 530px;
}
-
input[class*="span"],
select[class*="span"],
textarea[class*="span"],
@@ -1761,7 +1107,6 @@ textarea[class*="span"],
float: none;
margin-left: 0;
}
-
.input-append input[class*="span"],
.input-append .uneditable-input[class*="span"],
.input-prepend input[class*="span"],
@@ -1774,269 +1119,114 @@ textarea[class*="span"],
.row-fluid .input-append [class*="span"] {
display: inline-block;
}
-
input,
textarea,
.uneditable-input {
margin-left: 0;
}
-
.controls-row [class*="span"] + [class*="span"] {
margin-left: 20px;
}
-
input.span12,
textarea.span12,
.uneditable-input.span12 {
width: 926px;
}
-
input.span11,
textarea.span11,
.uneditable-input.span11 {
width: 846px;
}
-
input.span10,
textarea.span10,
.uneditable-input.span10 {
width: 766px;
}
-
input.span9,
textarea.span9,
.uneditable-input.span9 {
width: 686px;
}
-
input.span8,
textarea.span8,
.uneditable-input.span8 {
width: 606px;
}
-
input.span7,
textarea.span7,
.uneditable-input.span7 {
width: 526px;
}
-
input.span6,
textarea.span6,
.uneditable-input.span6 {
width: 446px;
}
-
input.span5,
textarea.span5,
.uneditable-input.span5 {
width: 366px;
}
-
input.span4,
textarea.span4,
.uneditable-input.span4 {
width: 286px;
}
-
input.span3,
textarea.span3,
.uneditable-input.span3 {
width: 206px;
}
-
input.span2,
textarea.span2,
.uneditable-input.span2 {
width: 126px;
}
-
input.span1,
textarea.span1,
.uneditable-input.span1 {
width: 46px;
}
-
-input,
-textarea,
-.uneditable-input {
- margin-left: 0;
+.controls-row {
+ *zoom: 1;
}
-
-.controls-row [class*="span"] + [class*="span"] {
- margin-left: 20px;
+.controls-row:before,
+.controls-row:after {
+ display: table;
+ content: "";
+ line-height: 0;
}
-
-input.span12,
-textarea.span12,
-.uneditable-input.span12 {
- width: 926px;
+.controls-row:after {
+ clear: both;
}
-
-input.span11,
-textarea.span11,
-.uneditable-input.span11 {
- width: 846px;
+.controls-row [class*="span"],
+.row-fluid .controls-row [class*="span"] {
+ float: left;
}
-
-input.span10,
-textarea.span10,
-.uneditable-input.span10 {
- width: 766px;
+.controls-row .checkbox[class*="span"],
+.controls-row .radio[class*="span"] {
+ padding-top: 5px;
}
-
-input.span9,
-textarea.span9,
-.uneditable-input.span9 {
- width: 686px;
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ cursor: not-allowed;
+ background-color: #eeeeee;
}
-
-input.span8,
-textarea.span8,
-.uneditable-input.span8 {
- width: 606px;
-}
-
-input.span7,
-textarea.span7,
-.uneditable-input.span7 {
- width: 526px;
-}
-
-input.span6,
-textarea.span6,
-.uneditable-input.span6 {
- width: 446px;
-}
-
-input.span5,
-textarea.span5,
-.uneditable-input.span5 {
- width: 366px;
-}
-
-input.span4,
-textarea.span4,
-.uneditable-input.span4 {
- width: 286px;
-}
-
-input.span3,
-textarea.span3,
-.uneditable-input.span3 {
- width: 206px;
-}
-
-input.span2,
-textarea.span2,
-.uneditable-input.span2 {
- width: 126px;
-}
-
-input.span1,
-textarea.span1,
-.uneditable-input.span1 {
- width: 46px;
-}
-
-.controls-row {
- *zoom: 1;
-}
-
-.controls-row:before,
-.controls-row:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.controls-row:after {
- clear: both;
-}
-
-.controls-row:before,
-.controls-row:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.controls-row:after {
- clear: both;
-}
-
-.controls-row [class*="span"],
-.row-fluid .controls-row [class*="span"] {
- float: left;
-}
-
-.controls-row .checkbox[class*="span"],
-.controls-row .radio[class*="span"] {
- padding-top: 5px;
-}
-
-input[disabled],
-select[disabled],
-textarea[disabled],
-input[readonly],
-select[readonly],
-textarea[readonly] {
- cursor: not-allowed;
- background-color: #eeeeee;
-}
-
input[type="radio"][disabled],
input[type="checkbox"][disabled],
input[type="radio"][readonly],
input[type="checkbox"][readonly] {
background-color: transparent;
}
-
-.control-group.warning .control-label,
-.control-group.warning .help-block,
-.control-group.warning .help-inline {
- color: #c09853;
-}
-
-.control-group.warning .checkbox,
-.control-group.warning .radio,
-.control-group.warning input,
-.control-group.warning select,
-.control-group.warning textarea {
- color: #c09853;
-}
-
-.control-group.warning input,
-.control-group.warning select,
-.control-group.warning textarea {
- border-color: #c09853;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.warning input:focus,
-.control-group.warning select:focus,
-.control-group.warning textarea:focus {
- border-color: #a47e3c;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
-}
-
-.control-group.warning .input-prepend .add-on,
-.control-group.warning .input-append .add-on {
- color: #c09853;
- background-color: #fcf8e3;
- border-color: #c09853;
-}
-
.control-group.warning .control-label,
.control-group.warning .help-block,
.control-group.warning .help-inline {
color: #c09853;
}
-
.control-group.warning .checkbox,
.control-group.warning .radio,
.control-group.warning input,
@@ -2044,77 +1234,33 @@ input[type="checkbox"][readonly] {
.control-group.warning textarea {
color: #c09853;
}
-
.control-group.warning input,
.control-group.warning select,
.control-group.warning textarea {
border-color: #c09853;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
-
.control-group.warning input:focus,
.control-group.warning select:focus,
.control-group.warning textarea:focus {
border-color: #a47e3c;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
}
-
.control-group.warning .input-prepend .add-on,
.control-group.warning .input-append .add-on {
color: #c09853;
background-color: #fcf8e3;
border-color: #c09853;
}
-
-.control-group.error .control-label,
-.control-group.error .help-block,
-.control-group.error .help-inline {
- color: #b94a48;
-}
-
-.control-group.error .checkbox,
-.control-group.error .radio,
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
- color: #b94a48;
-}
-
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
- border-color: #b94a48;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.error input:focus,
-.control-group.error select:focus,
-.control-group.error textarea:focus {
- border-color: #953b39;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
-}
-
-.control-group.error .input-prepend .add-on,
-.control-group.error .input-append .add-on {
- color: #b94a48;
- background-color: #f2dede;
- border-color: #b94a48;
-}
-
.control-group.error .control-label,
.control-group.error .help-block,
.control-group.error .help-inline {
color: #b94a48;
}
-
.control-group.error .checkbox,
.control-group.error .radio,
.control-group.error input,
@@ -2122,77 +1268,33 @@ input[type="checkbox"][readonly] {
.control-group.error textarea {
color: #b94a48;
}
-
.control-group.error input,
.control-group.error select,
.control-group.error textarea {
border-color: #b94a48;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
-
.control-group.error input:focus,
.control-group.error select:focus,
.control-group.error textarea:focus {
border-color: #953b39;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
}
-
.control-group.error .input-prepend .add-on,
.control-group.error .input-append .add-on {
color: #b94a48;
background-color: #f2dede;
border-color: #b94a48;
}
-
-.control-group.success .control-label,
-.control-group.success .help-block,
-.control-group.success .help-inline {
- color: #468847;
-}
-
-.control-group.success .checkbox,
-.control-group.success .radio,
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
- color: #468847;
-}
-
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
- border-color: #468847;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.success input:focus,
-.control-group.success select:focus,
-.control-group.success textarea:focus {
- border-color: #356635;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
-}
-
-.control-group.success .input-prepend .add-on,
-.control-group.success .input-append .add-on {
- color: #468847;
- background-color: #dff0d8;
- border-color: #468847;
-}
-
.control-group.success .control-label,
.control-group.success .help-block,
.control-group.success .help-inline {
color: #468847;
}
-
.control-group.success .checkbox,
.control-group.success .radio,
.control-group.success input,
@@ -2200,77 +1302,33 @@ input[type="checkbox"][readonly] {
.control-group.success textarea {
color: #468847;
}
-
.control-group.success input,
.control-group.success select,
.control-group.success textarea {
border-color: #468847;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
-
.control-group.success input:focus,
.control-group.success select:focus,
.control-group.success textarea:focus {
border-color: #356635;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
}
-
.control-group.success .input-prepend .add-on,
.control-group.success .input-append .add-on {
color: #468847;
background-color: #dff0d8;
border-color: #468847;
}
-
-.control-group.info .control-label,
-.control-group.info .help-block,
-.control-group.info .help-inline {
- color: #3a87ad;
-}
-
-.control-group.info .checkbox,
-.control-group.info .radio,
-.control-group.info input,
-.control-group.info select,
-.control-group.info textarea {
- color: #3a87ad;
-}
-
-.control-group.info input,
-.control-group.info select,
-.control-group.info textarea {
- border-color: #3a87ad;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.info input:focus,
-.control-group.info select:focus,
-.control-group.info textarea:focus {
- border-color: #2d6987;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
-}
-
-.control-group.info .input-prepend .add-on,
-.control-group.info .input-append .add-on {
- color: #3a87ad;
- background-color: #d9edf7;
- border-color: #3a87ad;
-}
-
.control-group.info .control-label,
.control-group.info .help-block,
.control-group.info .help-inline {
color: #3a87ad;
}
-
.control-group.info .checkbox,
.control-group.info .radio,
.control-group.info input,
@@ -2278,48 +1336,42 @@ input[type="checkbox"][readonly] {
.control-group.info textarea {
color: #3a87ad;
}
-
.control-group.info input,
.control-group.info select,
.control-group.info textarea {
border-color: #3a87ad;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
-
.control-group.info input:focus,
.control-group.info select:focus,
.control-group.info textarea:focus {
border-color: #2d6987;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
}
-
.control-group.info .input-prepend .add-on,
.control-group.info .input-append .add-on {
color: #3a87ad;
background-color: #d9edf7;
border-color: #3a87ad;
}
-
input:focus:invalid,
textarea:focus:invalid,
select:focus:invalid {
color: #b94a48;
border-color: #ee5f5b;
}
-
input:focus:invalid:focus,
textarea:focus:invalid:focus,
select:focus:invalid:focus {
border-color: #e9322d;
-webkit-box-shadow: 0 0 6px #f8b9b7;
- -moz-box-shadow: 0 0 6px #f8b9b7;
- box-shadow: 0 0 6px #f8b9b7;
+ -moz-box-shadow: 0 0 6px #f8b9b7;
+ box-shadow: 0 0 6px #f8b9b7;
}
-
.form-actions {
padding: 19px 20px 20px;
margin-top: 20px;
@@ -2328,56 +1380,39 @@ select:focus:invalid:focus {
border-top: 1px solid #e5e5e5;
*zoom: 1;
}
-
.form-actions:before,
.form-actions:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.form-actions:after {
- clear: both;
-}
-
-.form-actions:before,
-.form-actions:after {
- display: table;
line-height: 0;
- content: "";
}
-
.form-actions:after {
clear: both;
}
-
.help-block,
.help-inline {
color: #595959;
}
-
.help-block {
display: block;
margin-bottom: 10px;
}
-
.help-inline {
display: inline-block;
*display: inline;
- padding-left: 5px;
- vertical-align: middle;
+ /* IE7 inline-block hack */
*zoom: 1;
+ vertical-align: middle;
+ padding-left: 5px;
}
-
.input-append,
.input-prepend {
display: inline-block;
margin-bottom: 10px;
+ vertical-align: middle;
font-size: 0;
white-space: nowrap;
- vertical-align: middle;
}
-
.input-append input,
.input-prepend input,
.input-append select,
@@ -2390,7 +1425,6 @@ select:focus:invalid:focus {
.input-prepend .popover {
font-size: 14px;
}
-
.input-append input,
.input-prepend input,
.input-append select,
@@ -2402,10 +1436,9 @@ select:focus:invalid:focus {
*margin-left: 0;
vertical-align: top;
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.input-append input:focus,
.input-prepend input:focus,
.input-append select:focus,
@@ -2414,7 +1447,6 @@ select:focus:invalid:focus {
.input-prepend .uneditable-input:focus {
z-index: 2;
}
-
.input-append .add-on,
.input-prepend .add-on {
display: inline-block;
@@ -2430,7 +1462,6 @@ select:focus:invalid:focus {
background-color: #eeeeee;
border: 1px solid #ccc;
}
-
.input-append .add-on,
.input-prepend .add-on,
.input-append .btn,
@@ -2439,140 +1470,119 @@ select:focus:invalid:focus {
.input-prepend .btn-group > .dropdown-toggle {
vertical-align: top;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.input-append .active,
.input-prepend .active {
background-color: #a9dba9;
border-color: #46a546;
}
-
.input-prepend .add-on,
.input-prepend .btn {
margin-right: -1px;
}
-
.input-prepend .add-on:first-child,
.input-prepend .btn:first-child {
-webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
}
-
.input-append input,
.input-append select,
.input-append .uneditable-input {
-webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
}
-
.input-append input + .btn-group .btn:last-child,
.input-append select + .btn-group .btn:last-child,
.input-append .uneditable-input + .btn-group .btn:last-child {
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.input-append .add-on,
.input-append .btn,
.input-append .btn-group {
margin-left: -1px;
}
-
.input-append .add-on:last-child,
.input-append .btn:last-child,
.input-append .btn-group:last-child > .dropdown-toggle {
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.input-prepend.input-append input,
.input-prepend.input-append select,
.input-prepend.input-append .uneditable-input {
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.input-prepend.input-append input + .btn-group .btn,
.input-prepend.input-append select + .btn-group .btn,
.input-prepend.input-append .uneditable-input + .btn-group .btn {
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.input-prepend.input-append .add-on:first-child,
.input-prepend.input-append .btn:first-child {
margin-right: -1px;
-webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
}
-
.input-prepend.input-append .add-on:last-child,
.input-prepend.input-append .btn:last-child {
margin-left: -1px;
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.input-prepend.input-append .btn-group:first-child {
margin-left: 0;
}
-
input.search-query {
padding-right: 14px;
padding-right: 4px \9;
padding-left: 14px;
padding-left: 4px \9;
/* IE7-8 doesn't have border-radius, so don't indent the padding */
-
margin-bottom: 0;
-webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
}
-
/* Allow for input prepend/append in search forms */
-
.form-search .input-append .search-query,
.form-search .input-prepend .search-query {
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.form-search .input-append .search-query {
-webkit-border-radius: 14px 0 0 14px;
- -moz-border-radius: 14px 0 0 14px;
- border-radius: 14px 0 0 14px;
+ -moz-border-radius: 14px 0 0 14px;
+ border-radius: 14px 0 0 14px;
}
-
.form-search .input-append .btn {
-webkit-border-radius: 0 14px 14px 0;
- -moz-border-radius: 0 14px 14px 0;
- border-radius: 0 14px 14px 0;
+ -moz-border-radius: 0 14px 14px 0;
+ border-radius: 0 14px 14px 0;
}
-
.form-search .input-prepend .search-query {
-webkit-border-radius: 0 14px 14px 0;
- -moz-border-radius: 0 14px 14px 0;
- border-radius: 0 14px 14px 0;
+ -moz-border-radius: 0 14px 14px 0;
+ border-radius: 0 14px 14px 0;
}
-
.form-search .input-prepend .btn {
-webkit-border-radius: 14px 0 0 14px;
- -moz-border-radius: 14px 0 0 14px;
- border-radius: 14px 0 0 14px;
+ -moz-border-radius: 14px 0 0 14px;
+ border-radius: 14px 0 0 14px;
}
-
.form-search input,
.form-inline input,
.form-horizontal input,
@@ -2596,31 +1606,28 @@ input.search-query {
.form-horizontal .input-append {
display: inline-block;
*display: inline;
+ /* IE7 inline-block hack */
+ *zoom: 1;
margin-bottom: 0;
vertical-align: middle;
- *zoom: 1;
}
-
.form-search .hide,
.form-inline .hide,
.form-horizontal .hide {
display: none;
}
-
.form-search label,
.form-inline label,
.form-search .btn-group,
.form-inline .btn-group {
display: inline-block;
}
-
.form-search .input-append,
.form-inline .input-append,
.form-search .input-prepend,
.form-inline .input-prepend {
margin-bottom: 0;
}
-
.form-search .radio,
.form-search .checkbox,
.form-inline .radio,
@@ -2629,7 +1636,6 @@ input.search-query {
margin-bottom: 0;
vertical-align: middle;
}
-
.form-search .radio input[type="radio"],
.form-search .checkbox input[type="checkbox"],
.form-inline .radio input[type="radio"],
@@ -2638,65 +1644,44 @@ input.search-query {
margin-right: 3px;
margin-left: 0;
}
-
.control-group {
margin-bottom: 10px;
}
-
legend + .control-group {
margin-top: 20px;
-webkit-margin-top-collapse: separate;
}
-
.form-horizontal .control-group {
margin-bottom: 20px;
*zoom: 1;
}
-
.form-horizontal .control-group:before,
.form-horizontal .control-group:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.form-horizontal .control-group:after {
- clear: both;
-}
-
-.form-horizontal .control-group:before,
-.form-horizontal .control-group:after {
- display: table;
line-height: 0;
- content: "";
}
-
.form-horizontal .control-group:after {
clear: both;
}
-
.form-horizontal .control-label {
float: left;
width: 160px;
padding-top: 5px;
text-align: right;
}
-
.form-horizontal .controls {
*display: inline-block;
*padding-left: 20px;
margin-left: 180px;
*margin-left: 0;
}
-
.form-horizontal .controls:first-child {
*padding-left: 180px;
}
-
.form-horizontal .help-block {
margin-bottom: 0;
}
-
.form-horizontal input + .help-block,
.form-horizontal select + .help-block,
.form-horizontal textarea + .help-block,
@@ -2705,23 +1690,19 @@ legend + .control-group {
.form-horizontal .input-append + .help-block {
margin-top: 10px;
}
-
.form-horizontal .form-actions {
padding-left: 180px;
}
-
table {
max-width: 100%;
background-color: transparent;
border-collapse: collapse;
border-spacing: 0;
}
-
.table {
width: 100%;
margin-bottom: 20px;
}
-
.table th,
.table td {
padding: 8px;
@@ -2730,15 +1711,12 @@ table {
vertical-align: top;
border-top: 1px solid #dddddd;
}
-
.table th {
font-weight: bold;
}
-
.table thead th {
vertical-align: bottom;
}
-
.table caption + thead tr:first-child th,
.table caption + thead tr:first-child td,
.table colgroup + thead tr:first-child th,
@@ -2747,35 +1725,29 @@ table {
.table thead:first-child tr:first-child td {
border-top: 0;
}
-
.table tbody + tbody {
border-top: 2px solid #dddddd;
}
-
.table .table {
background-color: #ffffff;
}
-
.table-condensed th,
.table-condensed td {
padding: 4px 5px;
}
-
.table-bordered {
border: 1px solid #dddddd;
border-collapse: separate;
*border-collapse: collapse;
border-left: 0;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.table-bordered th,
.table-bordered td {
border-left: 1px solid #dddddd;
}
-
.table-bordered caption + thead tr:first-child th,
.table-bordered caption + tbody tr:first-child th,
.table-bordered caption + tbody tr:first-child td,
@@ -2787,83 +1759,72 @@ table {
.table-bordered tbody:first-child tr:first-child td {
border-top: 0;
}
-
.table-bordered thead:first-child tr:first-child > th:first-child,
.table-bordered tbody:first-child tr:first-child > td:first-child,
.table-bordered tbody:first-child tr:first-child > th:first-child {
-webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
}
-
.table-bordered thead:first-child tr:first-child > th:last-child,
.table-bordered tbody:first-child tr:first-child > td:last-child,
.table-bordered tbody:first-child tr:first-child > th:last-child {
-webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
}
-
.table-bordered thead:last-child tr:last-child > th:first-child,
.table-bordered tbody:last-child tr:last-child > td:first-child,
.table-bordered tbody:last-child tr:last-child > th:first-child,
.table-bordered tfoot:last-child tr:last-child > td:first-child,
.table-bordered tfoot:last-child tr:last-child > th:first-child {
-webkit-border-bottom-left-radius: 4px;
- border-bottom-left-radius: 4px;
-moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
}
-
.table-bordered thead:last-child tr:last-child > th:last-child,
.table-bordered tbody:last-child tr:last-child > td:last-child,
.table-bordered tbody:last-child tr:last-child > th:last-child,
.table-bordered tfoot:last-child tr:last-child > td:last-child,
.table-bordered tfoot:last-child tr:last-child > th:last-child {
-webkit-border-bottom-right-radius: 4px;
- border-bottom-right-radius: 4px;
-moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
}
-
.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
-webkit-border-bottom-left-radius: 0;
- border-bottom-left-radius: 0;
-moz-border-radius-bottomleft: 0;
+ border-bottom-left-radius: 0;
}
-
.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
-webkit-border-bottom-right-radius: 0;
- border-bottom-right-radius: 0;
-moz-border-radius-bottomright: 0;
+ border-bottom-right-radius: 0;
}
-
.table-bordered caption + thead tr:first-child th:first-child,
.table-bordered caption + tbody tr:first-child td:first-child,
.table-bordered colgroup + thead tr:first-child th:first-child,
.table-bordered colgroup + tbody tr:first-child td:first-child {
-webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
}
-
.table-bordered caption + thead tr:first-child th:last-child,
.table-bordered caption + tbody tr:first-child td:last-child,
.table-bordered colgroup + thead tr:first-child th:last-child,
.table-bordered colgroup + tbody tr:first-child td:last-child {
-webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
}
-
.table-striped tbody > tr:nth-child(odd) > td,
.table-striped tbody > tr:nth-child(odd) > th {
background-color: #f9f9f9;
}
-
.table-hover tbody tr:hover > td,
.table-hover tbody tr:hover > th {
background-color: #f5f5f5;
}
-
table td[class*="span"],
table th[class*="span"],
.row-fluid table td[class*="span"],
@@ -2872,139 +1833,116 @@ table th[class*="span"],
float: none;
margin-left: 0;
}
-
.table td.span1,
.table th.span1 {
float: none;
width: 44px;
margin-left: 0;
}
-
.table td.span2,
.table th.span2 {
float: none;
width: 124px;
margin-left: 0;
}
-
.table td.span3,
.table th.span3 {
float: none;
width: 204px;
margin-left: 0;
}
-
.table td.span4,
.table th.span4 {
float: none;
width: 284px;
margin-left: 0;
}
-
.table td.span5,
.table th.span5 {
float: none;
width: 364px;
margin-left: 0;
}
-
.table td.span6,
.table th.span6 {
float: none;
width: 444px;
margin-left: 0;
}
-
.table td.span7,
.table th.span7 {
float: none;
width: 524px;
margin-left: 0;
}
-
.table td.span8,
.table th.span8 {
float: none;
width: 604px;
margin-left: 0;
}
-
.table td.span9,
.table th.span9 {
float: none;
width: 684px;
margin-left: 0;
}
-
.table td.span10,
.table th.span10 {
float: none;
width: 764px;
margin-left: 0;
}
-
.table td.span11,
.table th.span11 {
float: none;
width: 844px;
margin-left: 0;
}
-
.table td.span12,
.table th.span12 {
float: none;
width: 924px;
margin-left: 0;
}
-
.table tbody tr.success > td {
background-color: #dff0d8;
}
-
.table tbody tr.error > td {
background-color: #f2dede;
}
-
.table tbody tr.warning > td {
background-color: #fcf8e3;
}
-
.table tbody tr.info > td {
background-color: #d9edf7;
}
-
.table-hover tbody tr.success:hover > td {
background-color: #d0e9c6;
}
-
.table-hover tbody tr.error:hover > td {
background-color: #ebcccc;
}
-
.table-hover tbody tr.warning:hover > td {
background-color: #faf2cc;
}
-
.table-hover tbody tr.info:hover > td {
background-color: #c4e3f3;
}
-
[class^="icon-"],
[class*=" icon-"] {
display: inline-block;
width: 14px;
height: 14px;
- margin-top: 1px;
*margin-right: .3em;
line-height: 14px;
vertical-align: text-top;
- background-image: url("../bower_components/bootstrap/img/glyphicons-halflings.png");
+ background-image: url("../img/glyphicons-halflings.png");
background-position: 14px 14px;
background-repeat: no-repeat;
+ margin-top: 1px;
}
-
/* White icons with optional class, or on hover/focus/active states of certain elements */
-
.icon-white,
.nav-pills > .active > a > [class^="icon-"],
.nav-pills > .active > a > [class*=" icon-"],
@@ -3022,586 +1960,442 @@ table th[class*="span"],
.dropdown-submenu:focus > a > [class^="icon-"],
.dropdown-submenu:hover > a > [class*=" icon-"],
.dropdown-submenu:focus > a > [class*=" icon-"] {
- background-image: url("../bower_components/bootstrap/img/glyphicons-halflings-white.png");
+ background-image: url("../img/glyphicons-halflings-white.png");
}
-
.icon-glass {
background-position: 0 0;
}
-
.icon-music {
background-position: -24px 0;
}
-
.icon-search {
background-position: -48px 0;
}
-
.icon-envelope {
background-position: -72px 0;
}
-
.icon-heart {
background-position: -96px 0;
}
-
.icon-star {
background-position: -120px 0;
}
-
.icon-star-empty {
background-position: -144px 0;
}
-
.icon-user {
background-position: -168px 0;
}
-
.icon-film {
background-position: -192px 0;
}
-
.icon-th-large {
background-position: -216px 0;
}
-
.icon-th {
background-position: -240px 0;
}
-
.icon-th-list {
background-position: -264px 0;
}
-
.icon-ok {
background-position: -288px 0;
}
-
.icon-remove {
background-position: -312px 0;
}
-
.icon-zoom-in {
background-position: -336px 0;
}
-
.icon-zoom-out {
background-position: -360px 0;
}
-
.icon-off {
background-position: -384px 0;
}
-
.icon-signal {
background-position: -408px 0;
}
-
.icon-cog {
background-position: -432px 0;
}
-
.icon-trash {
background-position: -456px 0;
}
-
.icon-home {
background-position: 0 -24px;
}
-
.icon-file {
background-position: -24px -24px;
}
-
.icon-time {
background-position: -48px -24px;
}
-
.icon-road {
background-position: -72px -24px;
}
-
.icon-download-alt {
background-position: -96px -24px;
}
-
.icon-download {
background-position: -120px -24px;
}
-
.icon-upload {
background-position: -144px -24px;
}
-
.icon-inbox {
background-position: -168px -24px;
}
-
.icon-play-circle {
background-position: -192px -24px;
}
-
.icon-repeat {
background-position: -216px -24px;
}
-
.icon-refresh {
background-position: -240px -24px;
}
-
.icon-list-alt {
background-position: -264px -24px;
}
-
.icon-lock {
background-position: -287px -24px;
}
-
.icon-flag {
background-position: -312px -24px;
}
-
.icon-headphones {
background-position: -336px -24px;
}
-
.icon-volume-off {
background-position: -360px -24px;
}
-
.icon-volume-down {
background-position: -384px -24px;
}
-
.icon-volume-up {
background-position: -408px -24px;
}
-
.icon-qrcode {
background-position: -432px -24px;
}
-
.icon-barcode {
background-position: -456px -24px;
}
-
.icon-tag {
background-position: 0 -48px;
}
-
.icon-tags {
background-position: -25px -48px;
}
-
.icon-book {
background-position: -48px -48px;
}
-
.icon-bookmark {
background-position: -72px -48px;
}
-
.icon-print {
background-position: -96px -48px;
}
-
.icon-camera {
background-position: -120px -48px;
}
-
.icon-font {
background-position: -144px -48px;
}
-
.icon-bold {
background-position: -167px -48px;
}
-
.icon-italic {
background-position: -192px -48px;
}
-
.icon-text-height {
background-position: -216px -48px;
}
-
.icon-text-width {
background-position: -240px -48px;
}
-
.icon-align-left {
background-position: -264px -48px;
}
-
.icon-align-center {
background-position: -288px -48px;
}
-
.icon-align-right {
background-position: -312px -48px;
}
-
.icon-align-justify {
background-position: -336px -48px;
}
-
.icon-list {
background-position: -360px -48px;
}
-
.icon-indent-left {
background-position: -384px -48px;
}
-
.icon-indent-right {
background-position: -408px -48px;
}
-
.icon-facetime-video {
background-position: -432px -48px;
}
-
.icon-picture {
background-position: -456px -48px;
}
-
.icon-pencil {
background-position: 0 -72px;
}
-
.icon-map-marker {
background-position: -24px -72px;
}
-
.icon-adjust {
background-position: -48px -72px;
}
-
.icon-tint {
background-position: -72px -72px;
}
-
.icon-edit {
background-position: -96px -72px;
}
-
.icon-share {
background-position: -120px -72px;
}
-
.icon-check {
background-position: -144px -72px;
}
-
.icon-move {
background-position: -168px -72px;
}
-
.icon-step-backward {
background-position: -192px -72px;
}
-
.icon-fast-backward {
background-position: -216px -72px;
}
-
.icon-backward {
background-position: -240px -72px;
}
-
.icon-play {
background-position: -264px -72px;
}
-
.icon-pause {
background-position: -288px -72px;
}
-
.icon-stop {
background-position: -312px -72px;
}
-
.icon-forward {
background-position: -336px -72px;
}
-
.icon-fast-forward {
background-position: -360px -72px;
}
-
.icon-step-forward {
background-position: -384px -72px;
}
-
.icon-eject {
background-position: -408px -72px;
}
-
.icon-chevron-left {
background-position: -432px -72px;
}
-
.icon-chevron-right {
background-position: -456px -72px;
}
-
.icon-plus-sign {
background-position: 0 -96px;
}
-
.icon-minus-sign {
background-position: -24px -96px;
}
-
.icon-remove-sign {
background-position: -48px -96px;
}
-
.icon-ok-sign {
background-position: -72px -96px;
}
-
.icon-question-sign {
background-position: -96px -96px;
}
-
.icon-info-sign {
background-position: -120px -96px;
}
-
.icon-screenshot {
background-position: -144px -96px;
}
-
.icon-remove-circle {
background-position: -168px -96px;
}
-
.icon-ok-circle {
background-position: -192px -96px;
}
-
.icon-ban-circle {
background-position: -216px -96px;
}
-
.icon-arrow-left {
background-position: -240px -96px;
}
-
.icon-arrow-right {
background-position: -264px -96px;
}
-
.icon-arrow-up {
background-position: -289px -96px;
}
-
.icon-arrow-down {
background-position: -312px -96px;
}
-
.icon-share-alt {
background-position: -336px -96px;
}
-
.icon-resize-full {
background-position: -360px -96px;
}
-
.icon-resize-small {
background-position: -384px -96px;
}
-
.icon-plus {
background-position: -408px -96px;
}
-
.icon-minus {
background-position: -433px -96px;
}
-
.icon-asterisk {
background-position: -456px -96px;
}
-
.icon-exclamation-sign {
background-position: 0 -120px;
}
-
.icon-gift {
background-position: -24px -120px;
}
-
.icon-leaf {
background-position: -48px -120px;
}
-
.icon-fire {
background-position: -72px -120px;
}
-
.icon-eye-open {
background-position: -96px -120px;
}
-
.icon-eye-close {
background-position: -120px -120px;
}
-
.icon-warning-sign {
background-position: -144px -120px;
}
-
.icon-plane {
background-position: -168px -120px;
}
-
.icon-calendar {
background-position: -192px -120px;
}
-
.icon-random {
- width: 16px;
background-position: -216px -120px;
+ width: 16px;
}
-
.icon-comment {
background-position: -240px -120px;
}
-
.icon-magnet {
background-position: -264px -120px;
}
-
.icon-chevron-up {
background-position: -288px -120px;
}
-
.icon-chevron-down {
background-position: -313px -119px;
}
-
.icon-retweet {
background-position: -336px -120px;
}
-
.icon-shopping-cart {
background-position: -360px -120px;
}
-
.icon-folder-close {
- width: 16px;
background-position: -384px -120px;
+ width: 16px;
}
-
.icon-folder-open {
- width: 16px;
background-position: -408px -120px;
+ width: 16px;
}
-
.icon-resize-vertical {
background-position: -432px -119px;
}
-
.icon-resize-horizontal {
background-position: -456px -118px;
}
-
.icon-hdd {
background-position: 0 -144px;
}
-
.icon-bullhorn {
background-position: -24px -144px;
}
-
.icon-bell {
background-position: -48px -144px;
}
-
.icon-certificate {
background-position: -72px -144px;
}
-
.icon-thumbs-up {
background-position: -96px -144px;
}
-
.icon-thumbs-down {
background-position: -120px -144px;
}
-
.icon-hand-right {
background-position: -144px -144px;
}
-
.icon-hand-left {
background-position: -168px -144px;
}
-
.icon-hand-up {
background-position: -192px -144px;
}
-
.icon-hand-down {
background-position: -216px -144px;
}
-
.icon-circle-arrow-right {
background-position: -240px -144px;
}
-
.icon-circle-arrow-left {
background-position: -264px -144px;
}
-
.icon-circle-arrow-up {
background-position: -288px -144px;
}
-
.icon-circle-arrow-down {
background-position: -312px -144px;
}
-
.icon-globe {
background-position: -336px -144px;
}
-
.icon-wrench {
background-position: -360px -144px;
}
-
.icon-tasks {
background-position: -384px -144px;
}
-
.icon-filter {
background-position: -408px -144px;
}
-
.icon-briefcase {
background-position: -432px -144px;
}
-
.icon-fullscreen {
background-position: -456px -144px;
}
-
.dropup,
.dropdown {
position: relative;
}
-
.dropdown-toggle {
*margin-bottom: -3px;
}
-
.dropdown-toggle:active,
.open .dropdown-toggle {
outline: 0;
}
-
.caret {
display: inline-block;
width: 0;
@@ -3612,12 +2406,10 @@ table th[class*="span"],
border-left: 4px solid transparent;
content: "";
}
-
.dropdown .caret {
margin-top: 8px;
margin-left: 2px;
}
-
.dropdown-menu {
position: absolute;
top: 100%;
@@ -3635,21 +2427,19 @@ table th[class*="span"],
*border-right-width: 2px;
*border-bottom-width: 2px;
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-webkit-background-clip: padding-box;
- -moz-background-clip: padding;
- background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
}
-
.dropdown-menu.pull-right {
right: 0;
left: auto;
}
-
.dropdown-menu .divider {
*width: 100%;
height: 1px;
@@ -3659,7 +2449,6 @@ table th[class*="span"],
background-color: #e5e5e5;
border-bottom: 1px solid #ffffff;
}
-
.dropdown-menu > li > a {
display: block;
padding: 3px 20px;
@@ -3669,13 +2458,12 @@ table th[class*="span"],
color: #333333;
white-space: nowrap;
}
-
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus,
.dropdown-submenu:hover > a,
.dropdown-submenu:focus > a {
- color: #ffffff;
text-decoration: none;
+ color: #ffffff;
background-color: #0081c2;
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
@@ -3685,12 +2473,12 @@ table th[class*="span"],
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
}
-
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
color: #ffffff;
text-decoration: none;
+ outline: 0;
background-color: #0081c2;
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
@@ -3698,132 +2486,112 @@ table th[class*="span"],
background-image: -o-linear-gradient(top, #0088cc, #0077b3);
background-image: linear-gradient(to bottom, #0088cc, #0077b3);
background-repeat: repeat-x;
- outline: 0;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
}
-
.dropdown-menu > .disabled > a,
.dropdown-menu > .disabled > a:hover,
.dropdown-menu > .disabled > a:focus {
color: #999999;
}
-
.dropdown-menu > .disabled > a:hover,
.dropdown-menu > .disabled > a:focus {
text-decoration: none;
- cursor: default;
background-color: transparent;
background-image: none;
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ cursor: default;
}
-
.open {
*z-index: 1000;
}
-
.open > .dropdown-menu {
display: block;
}
-
.dropdown-backdrop {
position: fixed;
- top: 0;
+ left: 0;
right: 0;
bottom: 0;
- left: 0;
+ top: 0;
z-index: 990;
}
-
.pull-right > .dropdown-menu {
right: 0;
left: auto;
}
-
.dropup .caret,
.navbar-fixed-bottom .dropdown .caret {
border-top: 0;
border-bottom: 4px solid #000000;
content: "";
}
-
.dropup .dropdown-menu,
.navbar-fixed-bottom .dropdown .dropdown-menu {
top: auto;
bottom: 100%;
margin-bottom: 1px;
}
-
.dropdown-submenu {
position: relative;
}
-
.dropdown-submenu > .dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
- -moz-border-radius: 0 6px 6px 6px;
- border-radius: 0 6px 6px 6px;
+ -moz-border-radius: 0 6px 6px 6px;
+ border-radius: 0 6px 6px 6px;
}
-
.dropdown-submenu:hover > .dropdown-menu {
display: block;
}
-
.dropup .dropdown-submenu > .dropdown-menu {
top: auto;
bottom: 0;
margin-top: 0;
margin-bottom: -2px;
-webkit-border-radius: 5px 5px 5px 0;
- -moz-border-radius: 5px 5px 5px 0;
- border-radius: 5px 5px 5px 0;
+ -moz-border-radius: 5px 5px 5px 0;
+ border-radius: 5px 5px 5px 0;
}
-
.dropdown-submenu > a:after {
display: block;
+ content: " ";
float: right;
width: 0;
height: 0;
- margin-top: 5px;
- margin-right: -10px;
border-color: transparent;
- border-left-color: #cccccc;
border-style: solid;
border-width: 5px 0 5px 5px;
- content: " ";
+ border-left-color: #cccccc;
+ margin-top: 5px;
+ margin-right: -10px;
}
-
.dropdown-submenu:hover > a:after {
border-left-color: #ffffff;
}
-
.dropdown-submenu.pull-left {
float: none;
}
-
.dropdown-submenu.pull-left > .dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
- -moz-border-radius: 6px 0 6px 6px;
- border-radius: 6px 0 6px 6px;
+ -moz-border-radius: 6px 0 6px 6px;
+ border-radius: 6px 0 6px 6px;
}
-
.dropdown .dropdown-menu .nav-header {
- padding-right: 20px;
padding-left: 20px;
+ padding-right: 20px;
}
-
.typeahead {
z-index: 1051;
margin-top: 2px;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.well {
min-height: 20px;
padding: 19px;
@@ -3831,58 +2599,50 @@ table th[class*="span"],
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
}
-
.well blockquote {
border-color: #ddd;
border-color: rgba(0, 0, 0, 0.15);
}
-
.well-large {
padding: 24px;
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
}
-
.well-small {
padding: 9px;
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
-
.fade {
opacity: 0;
-webkit-transition: opacity 0.15s linear;
- -moz-transition: opacity 0.15s linear;
- -o-transition: opacity 0.15s linear;
- transition: opacity 0.15s linear;
+ -moz-transition: opacity 0.15s linear;
+ -o-transition: opacity 0.15s linear;
+ transition: opacity 0.15s linear;
}
-
.fade.in {
opacity: 1;
}
-
.collapse {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition: height 0.35s ease;
- -moz-transition: height 0.35s ease;
- -o-transition: height 0.35s ease;
- transition: height 0.35s ease;
+ -moz-transition: height 0.35s ease;
+ -o-transition: height 0.35s ease;
+ transition: height 0.35s ease;
}
-
.collapse.in {
height: auto;
}
-
.close {
float: right;
font-size: 20px;
@@ -3893,7 +2653,6 @@ table th[class*="span"],
opacity: 0.2;
filter: alpha(opacity=20);
}
-
.close:hover,
.close:focus {
color: #000000;
@@ -3902,7 +2661,6 @@ table th[class*="span"],
opacity: 0.4;
filter: alpha(opacity=40);
}
-
button.close {
padding: 0;
cursor: pointer;
@@ -3910,60 +2668,44 @@ button.close {
border: 0;
-webkit-appearance: none;
}
-
.btn {
display: inline-block;
*display: inline;
+ /* IE7 inline-block hack */
+ *zoom: 1;
padding: 4px 12px;
margin-bottom: 0;
- *margin-left: .3em;
font-size: 14px;
line-height: 20px;
- color: #333333;
text-align: center;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
vertical-align: middle;
cursor: pointer;
+ color: #333333;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
background-color: #f5f5f5;
- *background-color: #e6e6e6;
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
background-repeat: repeat-x;
- border: 1px solid #cccccc;
- *border: 0;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ *background-color: #e6e6e6;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ border: 1px solid #cccccc;
+ *border: 0;
border-bottom-color: #b3b3b3;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
- *zoom: 1;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn:hover,
-.btn:focus,
-.btn:active,
-.btn.active,
-.btn.disabled,
-.btn[disabled] {
- color: #333333;
- background-color: #e6e6e6;
- *background-color: #d9d9d9;
-}
-
-.btn:active,
-.btn.active {
- background-color: #cccccc \9;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ *margin-left: .3em;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
}
-
.btn:hover,
.btn:focus,
.btn:active,
@@ -3974,46 +2716,36 @@ button.close {
background-color: #e6e6e6;
*background-color: #d9d9d9;
}
-
.btn:active,
.btn.active {
background-color: #cccccc \9;
}
-
-.btn:first-child {
- *margin-left: 0;
-}
-
.btn:first-child {
*margin-left: 0;
}
-
.btn:hover,
.btn:focus {
color: #333333;
text-decoration: none;
background-position: 0 -15px;
-webkit-transition: background-position 0.1s linear;
- -moz-transition: background-position 0.1s linear;
- -o-transition: background-position 0.1s linear;
- transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear;
}
-
.btn:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
-
.btn.active,
.btn:active {
background-image: none;
outline: 0;
- -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
}
-
.btn.disabled,
.btn[disabled] {
cursor: default;
@@ -4021,69 +2753,59 @@ button.close {
opacity: 0.65;
filter: alpha(opacity=65);
-webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
}
-
.btn-large {
padding: 11px 19px;
font-size: 17.5px;
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
}
-
.btn-large [class^="icon-"],
.btn-large [class*=" icon-"] {
margin-top: 4px;
}
-
.btn-small {
padding: 2px 10px;
font-size: 11.9px;
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
-
.btn-small [class^="icon-"],
.btn-small [class*=" icon-"] {
margin-top: 0;
}
-
.btn-mini [class^="icon-"],
.btn-mini [class*=" icon-"] {
margin-top: -1px;
}
-
.btn-mini {
padding: 0 6px;
font-size: 10.5px;
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
-
.btn-block {
display: block;
width: 100%;
- padding-right: 0;
padding-left: 0;
+ padding-right: 0;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
-
.btn-block + .btn-block {
margin-top: 5px;
}
-
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%;
}
-
.btn-primary.active,
.btn-warning.active,
.btn-danger.active,
@@ -4092,40 +2814,23 @@ input[type="button"].btn-block {
.btn-inverse.active {
color: rgba(255, 255, 255, 0.75);
}
-
.btn-primary {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #006dcc;
- *background-color: #0044cc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(to bottom, #0088cc, #0044cc);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-primary:hover,
-.btn-primary:focus,
-.btn-primary:active,
-.btn-primary.active,
-.btn-primary.disabled,
-.btn-primary[disabled] {
- color: #ffffff;
- background-color: #0044cc;
- *background-color: #003bb3;
-}
-
-.btn-primary:active,
-.btn-primary.active {
- background-color: #003399 \9;
+ *background-color: #0044cc;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
@@ -4136,45 +2841,27 @@ input[type="button"].btn-block {
background-color: #0044cc;
*background-color: #003bb3;
}
-
.btn-primary:active,
.btn-primary.active {
background-color: #003399 \9;
}
-
.btn-warning {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #faa732;
- *background-color: #f89406;
background-image: -moz-linear-gradient(top, #fbb450, #f89406);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
background-image: -o-linear-gradient(top, #fbb450, #f89406);
background-image: linear-gradient(to bottom, #fbb450, #f89406);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
border-color: #f89406 #f89406 #ad6704;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-warning:hover,
-.btn-warning:focus,
-.btn-warning:active,
-.btn-warning.active,
-.btn-warning.disabled,
-.btn-warning[disabled] {
- color: #ffffff;
- background-color: #f89406;
- *background-color: #df8505;
-}
-
-.btn-warning:active,
-.btn-warning.active {
- background-color: #c67605 \9;
+ *background-color: #f89406;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active,
@@ -4185,45 +2872,27 @@ input[type="button"].btn-block {
background-color: #f89406;
*background-color: #df8505;
}
-
.btn-warning:active,
.btn-warning.active {
background-color: #c67605 \9;
}
-
.btn-danger {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #da4f49;
- *background-color: #bd362f;
background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
border-color: #bd362f #bd362f #802420;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-danger:hover,
-.btn-danger:focus,
-.btn-danger:active,
-.btn-danger.active,
-.btn-danger.disabled,
-.btn-danger[disabled] {
- color: #ffffff;
- background-color: #bd362f;
- *background-color: #a9302a;
-}
-
-.btn-danger:active,
-.btn-danger.active {
- background-color: #942a25 \9;
+ *background-color: #bd362f;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active,
@@ -4234,45 +2903,27 @@ input[type="button"].btn-block {
background-color: #bd362f;
*background-color: #a9302a;
}
-
.btn-danger:active,
.btn-danger.active {
background-color: #942a25 \9;
}
-
.btn-success {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #5bb75b;
- *background-color: #51a351;
background-image: -moz-linear-gradient(top, #62c462, #51a351);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
background-image: -webkit-linear-gradient(top, #62c462, #51a351);
background-image: -o-linear-gradient(top, #62c462, #51a351);
background-image: linear-gradient(to bottom, #62c462, #51a351);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
border-color: #51a351 #51a351 #387038;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-success:hover,
-.btn-success:focus,
-.btn-success:active,
-.btn-success.active,
-.btn-success.disabled,
-.btn-success[disabled] {
- color: #ffffff;
- background-color: #51a351;
- *background-color: #499249;
-}
-
-.btn-success:active,
-.btn-success.active {
- background-color: #408140 \9;
+ *background-color: #51a351;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-success:hover,
.btn-success:focus,
.btn-success:active,
@@ -4283,45 +2934,27 @@ input[type="button"].btn-block {
background-color: #51a351;
*background-color: #499249;
}
-
.btn-success:active,
.btn-success.active {
background-color: #408140 \9;
}
-
.btn-info {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #49afcd;
- *background-color: #2f96b4;
background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
border-color: #2f96b4 #2f96b4 #1f6377;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-info:hover,
-.btn-info:focus,
-.btn-info:active,
-.btn-info.active,
-.btn-info.disabled,
-.btn-info[disabled] {
- color: #ffffff;
- background-color: #2f96b4;
- *background-color: #2a85a0;
-}
-
-.btn-info:active,
-.btn-info.active {
- background-color: #24748c \9;
+ *background-color: #2f96b4;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-info:hover,
.btn-info:focus,
.btn-info:active,
@@ -4332,45 +2965,27 @@ input[type="button"].btn-block {
background-color: #2f96b4;
*background-color: #2a85a0;
}
-
.btn-info:active,
.btn-info.active {
background-color: #24748c \9;
}
-
.btn-inverse {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #363636;
- *background-color: #222222;
background-image: -moz-linear-gradient(top, #444444, #222222);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
background-image: -webkit-linear-gradient(top, #444444, #222222);
background-image: -o-linear-gradient(top, #444444, #222222);
background-image: linear-gradient(to bottom, #444444, #222222);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
border-color: #222222 #222222 #000000;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-inverse:hover,
-.btn-inverse:focus,
-.btn-inverse:active,
-.btn-inverse.active,
-.btn-inverse.disabled,
-.btn-inverse[disabled] {
- color: #ffffff;
- background-color: #222222;
- *background-color: #151515;
-}
-
-.btn-inverse:active,
-.btn-inverse.active {
- background-color: #080808 \9;
+ *background-color: #222222;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.btn-inverse:hover,
.btn-inverse:focus,
.btn-inverse:active,
@@ -4381,278 +2996,230 @@ input[type="button"].btn-block {
background-color: #222222;
*background-color: #151515;
}
-
.btn-inverse:active,
.btn-inverse.active {
background-color: #080808 \9;
}
-
button.btn,
input[type="submit"].btn {
*padding-top: 3px;
*padding-bottom: 3px;
}
-
button.btn::-moz-focus-inner,
input[type="submit"].btn::-moz-focus-inner {
padding: 0;
border: 0;
}
-
button.btn.btn-large,
input[type="submit"].btn.btn-large {
*padding-top: 7px;
*padding-bottom: 7px;
}
-
button.btn.btn-small,
input[type="submit"].btn.btn-small {
*padding-top: 3px;
*padding-bottom: 3px;
}
-
button.btn.btn-mini,
input[type="submit"].btn.btn-mini {
*padding-top: 1px;
*padding-bottom: 1px;
}
-
.btn-link,
.btn-link:active,
.btn-link[disabled] {
background-color: transparent;
background-image: none;
-webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
}
-
.btn-link {
- color: #0088cc;
- cursor: pointer;
border-color: transparent;
+ cursor: pointer;
+ color: #0088cc;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.btn-link:hover,
.btn-link:focus {
color: #005580;
text-decoration: underline;
background-color: transparent;
}
-
.btn-link[disabled]:hover,
.btn-link[disabled]:focus {
color: #333333;
text-decoration: none;
}
-
.btn-group {
position: relative;
display: inline-block;
*display: inline;
- *margin-left: .3em;
+ /* IE7 inline-block hack */
+ *zoom: 1;
font-size: 0;
- white-space: nowrap;
vertical-align: middle;
- *zoom: 1;
-}
-
-.btn-group:first-child {
- *margin-left: 0;
+ white-space: nowrap;
+ *margin-left: .3em;
}
-
.btn-group:first-child {
*margin-left: 0;
}
-
.btn-group + .btn-group {
margin-left: 5px;
}
-
.btn-toolbar {
+ font-size: 0;
margin-top: 10px;
margin-bottom: 10px;
- font-size: 0;
}
-
.btn-toolbar > .btn + .btn,
.btn-toolbar > .btn-group + .btn,
.btn-toolbar > .btn + .btn-group {
margin-left: 5px;
}
-
.btn-group > .btn {
position: relative;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.btn-group > .btn + .btn {
margin-left: -1px;
}
-
.btn-group > .btn,
.btn-group > .dropdown-menu,
.btn-group > .popover {
font-size: 14px;
}
-
.btn-group > .btn-mini {
font-size: 10.5px;
}
-
.btn-group > .btn-small {
font-size: 11.9px;
}
-
.btn-group > .btn-large {
font-size: 17.5px;
}
-
.btn-group > .btn:first-child {
margin-left: 0;
- -webkit-border-bottom-left-radius: 4px;
- border-bottom-left-radius: 4px;
-webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
- -moz-border-radius-bottomleft: 4px;
-moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
}
-
.btn-group > .btn:last-child,
.btn-group > .dropdown-toggle {
-webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
- -webkit-border-bottom-right-radius: 4px;
- border-bottom-right-radius: 4px;
-moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
-moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
}
-
.btn-group > .btn.large:first-child {
margin-left: 0;
- -webkit-border-bottom-left-radius: 6px;
- border-bottom-left-radius: 6px;
-webkit-border-top-left-radius: 6px;
- border-top-left-radius: 6px;
- -moz-border-radius-bottomleft: 6px;
-moz-border-radius-topleft: 6px;
+ border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-bottom-left-radius: 6px;
}
-
.btn-group > .btn.large:last-child,
.btn-group > .large.dropdown-toggle {
-webkit-border-top-right-radius: 6px;
- border-top-right-radius: 6px;
- -webkit-border-bottom-right-radius: 6px;
- border-bottom-right-radius: 6px;
-moz-border-radius-topright: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
-moz-border-radius-bottomright: 6px;
+ border-bottom-right-radius: 6px;
}
-
.btn-group > .btn:hover,
.btn-group > .btn:focus,
.btn-group > .btn:active,
.btn-group > .btn.active {
z-index: 2;
}
-
.btn-group .dropdown-toggle:active,
.btn-group.open .dropdown-toggle {
outline: 0;
}
-
.btn-group > .btn + .dropdown-toggle {
- *padding-top: 5px;
+ padding-left: 8px;
padding-right: 8px;
+ -webkit-box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ -moz-box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ *padding-top: 5px;
*padding-bottom: 5px;
- padding-left: 8px;
- -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}
-
.btn-group > .btn-mini + .dropdown-toggle {
- *padding-top: 2px;
+ padding-left: 5px;
padding-right: 5px;
+ *padding-top: 2px;
*padding-bottom: 2px;
- padding-left: 5px;
}
-
.btn-group > .btn-small + .dropdown-toggle {
*padding-top: 5px;
*padding-bottom: 4px;
}
-
.btn-group > .btn-large + .dropdown-toggle {
- *padding-top: 7px;
+ padding-left: 12px;
padding-right: 12px;
+ *padding-top: 7px;
*padding-bottom: 7px;
- padding-left: 12px;
}
-
.btn-group.open .dropdown-toggle {
background-image: none;
- -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
+ box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
}
-
.btn-group.open .btn.dropdown-toggle {
background-color: #e6e6e6;
}
-
.btn-group.open .btn-primary.dropdown-toggle {
background-color: #0044cc;
}
-
.btn-group.open .btn-warning.dropdown-toggle {
background-color: #f89406;
}
-
.btn-group.open .btn-danger.dropdown-toggle {
background-color: #bd362f;
}
-
.btn-group.open .btn-success.dropdown-toggle {
background-color: #51a351;
}
-
.btn-group.open .btn-info.dropdown-toggle {
background-color: #2f96b4;
}
-
.btn-group.open .btn-inverse.dropdown-toggle {
background-color: #222222;
}
-
.btn .caret {
margin-top: 8px;
margin-left: 0;
}
-
.btn-large .caret {
margin-top: 6px;
}
-
.btn-large .caret {
- border-top-width: 5px;
- border-right-width: 5px;
border-left-width: 5px;
+ border-right-width: 5px;
+ border-top-width: 5px;
}
-
.btn-mini .caret,
.btn-small .caret {
margin-top: 8px;
}
-
.dropup .btn-large .caret {
border-bottom-width: 5px;
}
-
.btn-primary .caret,
.btn-warning .caret,
.btn-danger .caret,
@@ -4662,53 +3229,44 @@ input[type="submit"].btn.btn-mini {
border-top-color: #ffffff;
border-bottom-color: #ffffff;
}
-
.btn-group-vertical {
display: inline-block;
*display: inline;
/* IE7 inline-block hack */
-
*zoom: 1;
}
-
.btn-group-vertical > .btn {
display: block;
float: none;
max-width: 100%;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.btn-group-vertical > .btn + .btn {
- margin-top: -1px;
margin-left: 0;
+ margin-top: -1px;
}
-
.btn-group-vertical > .btn:first-child {
-webkit-border-radius: 4px 4px 0 0;
- -moz-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
}
-
.btn-group-vertical > .btn:last-child {
-webkit-border-radius: 0 0 4px 4px;
- -moz-border-radius: 0 0 4px 4px;
- border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
}
-
.btn-group-vertical > .btn-large:first-child {
-webkit-border-radius: 6px 6px 0 0;
- -moz-border-radius: 6px 6px 0 0;
- border-radius: 6px 6px 0 0;
+ -moz-border-radius: 6px 6px 0 0;
+ border-radius: 6px 6px 0 0;
}
-
.btn-group-vertical > .btn-large:last-child {
-webkit-border-radius: 0 0 6px 6px;
- -moz-border-radius: 0 0 6px 6px;
- border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
}
-
.alert {
padding: 8px 35px 8px 14px;
margin-bottom: 20px;
@@ -4716,96 +3274,78 @@ input[type="submit"].btn.btn-mini {
background-color: #fcf8e3;
border: 1px solid #fbeed5;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.alert,
.alert h4 {
color: #c09853;
}
-
.alert h4 {
margin: 0;
}
-
.alert .close {
position: relative;
top: -2px;
right: -21px;
line-height: 20px;
}
-
.alert-success {
- color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
+ color: #468847;
}
-
.alert-success h4 {
color: #468847;
}
-
.alert-danger,
.alert-error {
- color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
+ color: #b94a48;
}
-
.alert-danger h4,
.alert-error h4 {
color: #b94a48;
}
-
.alert-info {
- color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
+ color: #3a87ad;
}
-
.alert-info h4 {
color: #3a87ad;
}
-
.alert-block {
padding-top: 14px;
padding-bottom: 14px;
}
-
.alert-block > p,
.alert-block > ul {
margin-bottom: 0;
}
-
.alert-block p + p {
margin-top: 5px;
}
-
.nav {
- margin-bottom: 20px;
margin-left: 0;
+ margin-bottom: 20px;
list-style: none;
}
-
.nav > li > a {
display: block;
}
-
.nav > li > a:hover,
.nav > li > a:focus {
text-decoration: none;
background-color: #eeeeee;
}
-
.nav > li > a > img {
max-width: none;
}
-
.nav > .pull-right {
float: right;
}
-
.nav-header {
display: block;
padding: 3px 15px;
@@ -4816,28 +3356,23 @@ input[type="submit"].btn.btn-mini {
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-transform: uppercase;
}
-
.nav li + .nav-header {
margin-top: 9px;
}
-
.nav-list {
- padding-right: 15px;
padding-left: 15px;
+ padding-right: 15px;
margin-bottom: 0;
}
-
.nav-list > li > a,
.nav-list .nav-header {
- margin-right: -15px;
margin-left: -15px;
+ margin-right: -15px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
}
-
.nav-list > li > a {
padding: 3px 15px;
}
-
.nav-list > .active > a,
.nav-list > .active > a:hover,
.nav-list > .active > a:focus {
@@ -4845,12 +3380,10 @@ input[type="submit"].btn.btn-mini {
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
background-color: #0088cc;
}
-
.nav-list [class^="icon-"],
.nav-list [class*=" icon-"] {
margin-right: 2px;
}
-
.nav-list .divider {
*width: 100%;
height: 1px;
@@ -4860,45 +3393,26 @@ input[type="submit"].btn.btn-mini {
background-color: #e5e5e5;
border-bottom: 1px solid #ffffff;
}
-
.nav-tabs,
.nav-pills {
*zoom: 1;
}
-
.nav-tabs:before,
.nav-pills:before,
.nav-tabs:after,
.nav-pills:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.nav-tabs:after,
-.nav-pills:after {
- clear: both;
-}
-
-.nav-tabs:before,
-.nav-pills:before,
-.nav-tabs:after,
-.nav-pills:after {
- display: table;
line-height: 0;
- content: "";
}
-
.nav-tabs:after,
.nav-pills:after {
clear: both;
}
-
.nav-tabs > li,
.nav-pills > li {
float: left;
}
-
.nav-tabs > li > a,
.nav-pills > li > a {
padding-right: 12px;
@@ -4906,153 +3420,127 @@ input[type="submit"].btn.btn-mini {
margin-right: 2px;
line-height: 14px;
}
-
.nav-tabs {
border-bottom: 1px solid #ddd;
}
-
.nav-tabs > li {
margin-bottom: -1px;
}
-
.nav-tabs > li > a {
padding-top: 8px;
padding-bottom: 8px;
line-height: 20px;
border: 1px solid transparent;
-webkit-border-radius: 4px 4px 0 0;
- -moz-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
}
-
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
border-color: #eeeeee #eeeeee #dddddd;
}
-
.nav-tabs > .active > a,
.nav-tabs > .active > a:hover,
.nav-tabs > .active > a:focus {
color: #555555;
- cursor: default;
background-color: #ffffff;
border: 1px solid #ddd;
border-bottom-color: transparent;
+ cursor: default;
}
-
.nav-pills > li > a {
padding-top: 8px;
padding-bottom: 8px;
margin-top: 2px;
margin-bottom: 2px;
-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
}
-
.nav-pills > .active > a,
.nav-pills > .active > a:hover,
.nav-pills > .active > a:focus {
color: #ffffff;
background-color: #0088cc;
}
-
.nav-stacked > li {
float: none;
}
-
.nav-stacked > li > a {
margin-right: 0;
}
-
.nav-tabs.nav-stacked {
border-bottom: 0;
}
-
.nav-tabs.nav-stacked > li > a {
border: 1px solid #ddd;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.nav-tabs.nav-stacked > li:first-child > a {
-webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
- -webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
-moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
}
-
.nav-tabs.nav-stacked > li:last-child > a {
-webkit-border-bottom-right-radius: 4px;
- border-bottom-right-radius: 4px;
- -webkit-border-bottom-left-radius: 4px;
- border-bottom-left-radius: 4px;
-moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
-moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
}
-
.nav-tabs.nav-stacked > li > a:hover,
.nav-tabs.nav-stacked > li > a:focus {
- z-index: 2;
border-color: #ddd;
+ z-index: 2;
}
-
.nav-pills.nav-stacked > li > a {
margin-bottom: 3px;
}
-
.nav-pills.nav-stacked > li:last-child > a {
margin-bottom: 1px;
}
-
.nav-tabs .dropdown-menu {
-webkit-border-radius: 0 0 6px 6px;
- -moz-border-radius: 0 0 6px 6px;
- border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
}
-
.nav-pills .dropdown-menu {
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
}
-
.nav .dropdown-toggle .caret {
- margin-top: 6px;
border-top-color: #0088cc;
border-bottom-color: #0088cc;
+ margin-top: 6px;
}
-
.nav .dropdown-toggle:hover .caret,
.nav .dropdown-toggle:focus .caret {
border-top-color: #005580;
border-bottom-color: #005580;
}
-
/* move down carets for tabs */
-
.nav-tabs .dropdown-toggle .caret {
margin-top: 8px;
}
-
.nav .active .dropdown-toggle .caret {
border-top-color: #fff;
border-bottom-color: #fff;
}
-
.nav-tabs .active .dropdown-toggle .caret {
border-top-color: #555555;
border-bottom-color: #555555;
}
-
.nav > .dropdown.active > a:hover,
.nav > .dropdown.active > a:focus {
cursor: pointer;
}
-
.nav-tabs .open .dropdown-toggle,
.nav-pills .open .dropdown-toggle,
.nav > li.dropdown.open.active > a:hover,
@@ -5061,7 +3549,6 @@ input[type="submit"].btn.btn-mini {
background-color: #999999;
border-color: #999999;
}
-
.nav li.dropdown.open .caret,
.nav li.dropdown.open.active .caret,
.nav li.dropdown.open a:hover .caret,
@@ -5071,169 +3558,131 @@ input[type="submit"].btn.btn-mini {
opacity: 1;
filter: alpha(opacity=100);
}
-
.tabs-stacked .open > a:hover,
.tabs-stacked .open > a:focus {
border-color: #999999;
}
-
.tabbable {
*zoom: 1;
}
-
.tabbable:before,
.tabbable:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.tabbable:after {
- clear: both;
-}
-
-.tabbable:before,
-.tabbable:after {
- display: table;
line-height: 0;
- content: "";
}
-
.tabbable:after {
clear: both;
}
-
.tab-content {
overflow: auto;
}
-
.tabs-below > .nav-tabs,
.tabs-right > .nav-tabs,
.tabs-left > .nav-tabs {
border-bottom: 0;
}
-
.tab-content > .tab-pane,
.pill-content > .pill-pane {
display: none;
}
-
.tab-content > .active,
.pill-content > .active {
display: block;
}
-
.tabs-below > .nav-tabs {
border-top: 1px solid #ddd;
}
-
.tabs-below > .nav-tabs > li {
margin-top: -1px;
margin-bottom: 0;
}
-
.tabs-below > .nav-tabs > li > a {
-webkit-border-radius: 0 0 4px 4px;
- -moz-border-radius: 0 0 4px 4px;
- border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
}
-
.tabs-below > .nav-tabs > li > a:hover,
.tabs-below > .nav-tabs > li > a:focus {
- border-top-color: #ddd;
border-bottom-color: transparent;
+ border-top-color: #ddd;
}
-
.tabs-below > .nav-tabs > .active > a,
.tabs-below > .nav-tabs > .active > a:hover,
.tabs-below > .nav-tabs > .active > a:focus {
border-color: transparent #ddd #ddd #ddd;
}
-
.tabs-left > .nav-tabs > li,
.tabs-right > .nav-tabs > li {
float: none;
}
-
.tabs-left > .nav-tabs > li > a,
.tabs-right > .nav-tabs > li > a {
min-width: 74px;
margin-right: 0;
margin-bottom: 3px;
}
-
.tabs-left > .nav-tabs {
float: left;
margin-right: 19px;
border-right: 1px solid #ddd;
}
-
.tabs-left > .nav-tabs > li > a {
margin-right: -1px;
-webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
}
-
.tabs-left > .nav-tabs > li > a:hover,
.tabs-left > .nav-tabs > li > a:focus {
border-color: #eeeeee #dddddd #eeeeee #eeeeee;
}
-
.tabs-left > .nav-tabs .active > a,
.tabs-left > .nav-tabs .active > a:hover,
.tabs-left > .nav-tabs .active > a:focus {
border-color: #ddd transparent #ddd #ddd;
*border-right-color: #ffffff;
}
-
.tabs-right > .nav-tabs {
float: right;
margin-left: 19px;
border-left: 1px solid #ddd;
}
-
.tabs-right > .nav-tabs > li > a {
margin-left: -1px;
-webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
}
-
.tabs-right > .nav-tabs > li > a:hover,
.tabs-right > .nav-tabs > li > a:focus {
border-color: #eeeeee #eeeeee #eeeeee #dddddd;
}
-
.tabs-right > .nav-tabs .active > a,
.tabs-right > .nav-tabs .active > a:hover,
.tabs-right > .nav-tabs .active > a:focus {
border-color: #ddd #ddd #ddd transparent;
*border-left-color: #ffffff;
}
-
.nav > .disabled > a {
color: #999999;
}
-
.nav > .disabled > a:hover,
.nav > .disabled > a:focus {
text-decoration: none;
- cursor: default;
background-color: transparent;
+ cursor: default;
}
-
.navbar {
+ overflow: visible;
+ margin-bottom: 20px;
*position: relative;
*z-index: 2;
- margin-bottom: 20px;
- overflow: visible;
}
-
.navbar-inner {
min-height: 40px;
- padding-right: 20px;
padding-left: 20px;
+ padding-right: 20px;
background-color: #fafafa;
background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));
@@ -5241,51 +3690,35 @@ input[type="submit"].btn.btn-mini {
background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);
background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
border: 1px solid #d4d4d4;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
- *zoom: 1;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
- -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+ *zoom: 1;
}
-
.navbar-inner:before,
.navbar-inner:after {
display: table;
- line-height: 0;
content: "";
+ line-height: 0;
}
-
.navbar-inner:after {
clear: both;
}
-
-.navbar-inner:before,
-.navbar-inner:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.navbar-inner:after {
- clear: both;
-}
-
.navbar .container {
width: auto;
}
-
.nav-collapse.collapse {
height: auto;
overflow: visible;
}
-
.navbar .brand {
- display: block;
float: left;
+ display: block;
padding: 10px 20px 10px;
margin-left: -20px;
font-size: 20px;
@@ -5293,39 +3726,32 @@ input[type="submit"].btn.btn-mini {
color: #777777;
text-shadow: 0 1px 0 #ffffff;
}
-
.navbar .brand:hover,
.navbar .brand:focus {
text-decoration: none;
}
-
.navbar-text {
margin-bottom: 0;
line-height: 40px;
color: #777777;
}
-
.navbar-link {
color: #777777;
}
-
.navbar-link:hover,
.navbar-link:focus {
color: #333333;
}
-
.navbar .divider-vertical {
height: 40px;
margin: 0 9px;
- border-right: 1px solid #ffffff;
border-left: 1px solid #f2f2f2;
+ border-right: 1px solid #ffffff;
}
-
.navbar .btn,
.navbar .btn-group {
margin-top: 5px;
}
-
.navbar .btn-group .btn,
.navbar .input-prepend .btn,
.navbar .input-append .btn,
@@ -5333,95 +3759,71 @@ input[type="submit"].btn.btn-mini {
.navbar .input-append .btn-group {
margin-top: 0;
}
-
.navbar-form {
margin-bottom: 0;
*zoom: 1;
}
-
.navbar-form:before,
.navbar-form:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.navbar-form:after {
- clear: both;
-}
-
-.navbar-form:before,
-.navbar-form:after {
- display: table;
line-height: 0;
- content: "";
}
-
.navbar-form:after {
clear: both;
}
-
.navbar-form input,
.navbar-form select,
.navbar-form .radio,
.navbar-form .checkbox {
margin-top: 5px;
}
-
.navbar-form input,
.navbar-form select,
.navbar-form .btn {
display: inline-block;
margin-bottom: 0;
}
-
.navbar-form input[type="image"],
.navbar-form input[type="checkbox"],
.navbar-form input[type="radio"] {
margin-top: 3px;
}
-
.navbar-form .input-append,
.navbar-form .input-prepend {
margin-top: 5px;
white-space: nowrap;
}
-
.navbar-form .input-append input,
.navbar-form .input-prepend input {
margin-top: 0;
}
-
.navbar-search {
position: relative;
float: left;
margin-top: 5px;
margin-bottom: 0;
}
-
.navbar-search .search-query {
- padding: 4px 14px;
margin-bottom: 0;
+ padding: 4px 14px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
font-weight: normal;
line-height: 1;
-webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
}
-
.navbar-static-top {
position: static;
margin-bottom: 0;
}
-
.navbar-static-top .navbar-inner {
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.navbar-fixed-top,
.navbar-fixed-bottom {
position: fixed;
@@ -5430,52 +3832,43 @@ input[type="submit"].btn.btn-mini {
z-index: 1030;
margin-bottom: 0;
}
-
.navbar-fixed-top .navbar-inner,
.navbar-static-top .navbar-inner {
border-width: 0 0 1px;
}
-
.navbar-fixed-bottom .navbar-inner {
border-width: 1px 0 0;
}
-
.navbar-fixed-top .navbar-inner,
.navbar-fixed-bottom .navbar-inner {
- padding-right: 0;
padding-left: 0;
+ padding-right: 0;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
}
-
.navbar-static-top .container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 940px;
}
-
.navbar-fixed-top {
top: 0;
}
-
.navbar-fixed-top .navbar-inner,
.navbar-static-top .navbar-inner {
- -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
- -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
- box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+ -webkit-box-shadow: 0 1px 10px rgba(0,0,0,.1);
+ -moz-box-shadow: 0 1px 10px rgba(0,0,0,.1);
+ box-shadow: 0 1px 10px rgba(0,0,0,.1);
}
-
.navbar-fixed-bottom {
bottom: 0;
}
-
.navbar-fixed-bottom .navbar-inner {
- -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
- -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
- box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+ -webkit-box-shadow: 0 -1px 10px rgba(0,0,0,.1);
+ -moz-box-shadow: 0 -1px 10px rgba(0,0,0,.1);
+ box-shadow: 0 -1px 10px rgba(0,0,0,.1);
}
-
.navbar .nav {
position: relative;
left: 0;
@@ -5483,16 +3876,13 @@ input[type="submit"].btn.btn-mini {
float: left;
margin: 0 10px 0 0;
}
-
.navbar .nav.pull-right {
float: right;
margin-right: 0;
}
-
.navbar .nav > li {
float: left;
}
-
.navbar .nav > li > a {
float: none;
padding: 10px 15px 10px;
@@ -5500,18 +3890,15 @@ input[type="submit"].btn.btn-mini {
text-decoration: none;
text-shadow: 0 1px 0 #ffffff;
}
-
.navbar .nav .dropdown-toggle .caret {
margin-top: 8px;
}
-
.navbar .nav > li > a:focus,
.navbar .nav > li > a:hover {
+ background-color: transparent;
color: #333333;
text-decoration: none;
- background-color: transparent;
}
-
.navbar .nav > .active > a,
.navbar .nav > .active > a:hover,
.navbar .nav > .active > a:focus {
@@ -5519,51 +3906,34 @@ input[type="submit"].btn.btn-mini {
text-decoration: none;
background-color: #e5e5e5;
-webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
- -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
- box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+ -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
}
-
.navbar .btn-navbar {
display: none;
float: right;
padding: 7px 10px;
- margin-right: 5px;
margin-left: 5px;
+ margin-right: 5px;
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #ededed;
- *background-color: #e5e5e5;
background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));
background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5);
background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5);
background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);
border-color: #e5e5e5 #e5e5e5 #bfbfbf;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-}
-
-.navbar .btn-navbar:hover,
-.navbar .btn-navbar:focus,
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active,
-.navbar .btn-navbar.disabled,
-.navbar .btn-navbar[disabled] {
- color: #ffffff;
- background-color: #e5e5e5;
- *background-color: #d9d9d9;
-}
-
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active {
- background-color: #cccccc \9;
+ *background-color: #e5e5e5;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
+ -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
}
-
.navbar .btn-navbar:hover,
.navbar .btn-navbar:focus,
.navbar .btn-navbar:active,
@@ -5574,121 +3944,105 @@ input[type="submit"].btn.btn-mini {
background-color: #e5e5e5;
*background-color: #d9d9d9;
}
-
.navbar .btn-navbar:active,
.navbar .btn-navbar.active {
background-color: #cccccc \9;
}
-
.navbar .btn-navbar .icon-bar {
display: block;
width: 18px;
height: 2px;
background-color: #f5f5f5;
-webkit-border-radius: 1px;
- -moz-border-radius: 1px;
- border-radius: 1px;
+ -moz-border-radius: 1px;
+ border-radius: 1px;
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
- -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}
-
.btn-navbar .icon-bar + .icon-bar {
margin-top: 3px;
}
-
.navbar .nav > li > .dropdown-menu:before {
- position: absolute;
- top: -7px;
- left: 9px;
+ content: '';
display: inline-block;
+ border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
- border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
- content: '';
+ position: absolute;
+ top: -7px;
+ left: 9px;
}
-
.navbar .nav > li > .dropdown-menu:after {
- position: absolute;
- top: -6px;
- left: 10px;
+ content: '';
display: inline-block;
+ border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
- border-left: 6px solid transparent;
- content: '';
+ position: absolute;
+ top: -6px;
+ left: 10px;
}
-
.navbar-fixed-bottom .nav > li > .dropdown-menu:before {
- top: auto;
- bottom: -7px;
border-top: 7px solid #ccc;
- border-bottom: 0;
border-top-color: rgba(0, 0, 0, 0.2);
+ border-bottom: 0;
+ bottom: -7px;
+ top: auto;
}
-
.navbar-fixed-bottom .nav > li > .dropdown-menu:after {
- top: auto;
- bottom: -6px;
border-top: 6px solid #ffffff;
border-bottom: 0;
+ bottom: -6px;
+ top: auto;
}
-
.navbar .nav li.dropdown > a:hover .caret,
.navbar .nav li.dropdown > a:focus .caret {
border-top-color: #333333;
border-bottom-color: #333333;
}
-
.navbar .nav li.dropdown.open > .dropdown-toggle,
.navbar .nav li.dropdown.active > .dropdown-toggle,
.navbar .nav li.dropdown.open.active > .dropdown-toggle {
- color: #555555;
background-color: #e5e5e5;
+ color: #555555;
}
-
.navbar .nav li.dropdown > .dropdown-toggle .caret {
border-top-color: #777777;
border-bottom-color: #777777;
}
-
.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
.navbar .nav li.dropdown.active > .dropdown-toggle .caret,
.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {
border-top-color: #555555;
border-bottom-color: #555555;
}
-
.navbar .pull-right > li > .dropdown-menu,
.navbar .nav > li > .dropdown-menu.pull-right {
- right: 0;
left: auto;
+ right: 0;
}
-
.navbar .pull-right > li > .dropdown-menu:before,
.navbar .nav > li > .dropdown-menu.pull-right:before {
- right: 12px;
left: auto;
+ right: 12px;
}
-
.navbar .pull-right > li > .dropdown-menu:after,
.navbar .nav > li > .dropdown-menu.pull-right:after {
- right: 13px;
left: auto;
+ right: 13px;
}
-
.navbar .pull-right > li > .dropdown-menu .dropdown-menu,
.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu {
- right: 100%;
left: auto;
- margin-right: -1px;
+ right: 100%;
margin-left: 0;
+ margin-right: -1px;
-webkit-border-radius: 6px 0 6px 6px;
- -moz-border-radius: 6px 0 6px 6px;
- border-radius: 6px 0 6px 6px;
+ -moz-border-radius: 6px 0 6px 6px;
+ border-radius: 6px 0 6px 6px;
}
-
.navbar-inverse .navbar-inner {
background-color: #1b1b1b;
background-image: -moz-linear-gradient(top, #222222, #111111);
@@ -5697,120 +4051,90 @@ input[type="submit"].btn.btn-mini {
background-image: -o-linear-gradient(top, #222222, #111111);
background-image: linear-gradient(to bottom, #222222, #111111);
background-repeat: repeat-x;
- border-color: #252525;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
+ border-color: #252525;
}
-
.navbar-inverse .brand,
.navbar-inverse .nav > li > a {
color: #999999;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
-
.navbar-inverse .brand:hover,
.navbar-inverse .nav > li > a:hover,
.navbar-inverse .brand:focus,
.navbar-inverse .nav > li > a:focus {
color: #ffffff;
}
-
.navbar-inverse .brand {
color: #999999;
}
-
.navbar-inverse .navbar-text {
color: #999999;
}
-
.navbar-inverse .nav > li > a:focus,
.navbar-inverse .nav > li > a:hover {
- color: #ffffff;
background-color: transparent;
+ color: #ffffff;
}
-
.navbar-inverse .nav .active > a,
.navbar-inverse .nav .active > a:hover,
.navbar-inverse .nav .active > a:focus {
color: #ffffff;
background-color: #111111;
}
-
.navbar-inverse .navbar-link {
color: #999999;
}
-
.navbar-inverse .navbar-link:hover,
.navbar-inverse .navbar-link:focus {
color: #ffffff;
}
-
.navbar-inverse .divider-vertical {
- border-right-color: #222222;
border-left-color: #111111;
+ border-right-color: #222222;
}
-
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle,
.navbar-inverse .nav li.dropdown.active > .dropdown-toggle,
.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle {
- color: #ffffff;
background-color: #111111;
+ color: #ffffff;
}
-
.navbar-inverse .nav li.dropdown > a:hover .caret,
.navbar-inverse .nav li.dropdown > a:focus .caret {
border-top-color: #ffffff;
border-bottom-color: #ffffff;
}
-
.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {
border-top-color: #999999;
border-bottom-color: #999999;
}
-
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret,
.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret {
border-top-color: #ffffff;
border-bottom-color: #ffffff;
}
-
.navbar-inverse .navbar-search .search-query {
color: #ffffff;
background-color: #515151;
border-color: #111111;
- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+ -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);
+ -moz-box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);
+ box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);
-webkit-transition: none;
- -moz-transition: none;
- -o-transition: none;
- transition: none;
-}
-
-.navbar-inverse .navbar-search .search-query:-moz-placeholder {
- color: #cccccc;
-}
-
-.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {
- color: #cccccc;
+ -moz-transition: none;
+ -o-transition: none;
+ transition: none;
}
-
-.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {
- color: #cccccc;
-}
-
.navbar-inverse .navbar-search .search-query:-moz-placeholder {
color: #cccccc;
}
-
.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {
color: #cccccc;
}
-
.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {
color: #cccccc;
}
-
.navbar-inverse .navbar-search .search-query:focus,
.navbar-inverse .navbar-search .search-query.focused {
padding: 5px 15px;
@@ -5818,45 +4142,28 @@ input[type="submit"].btn.btn-mini {
text-shadow: 0 1px 0 #ffffff;
background-color: #ffffff;
border: 0;
- outline: 0;
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
- -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ outline: 0;
}
-
.navbar-inverse .btn-navbar {
color: #ffffff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #0e0e0e;
- *background-color: #040404;
background-image: -moz-linear-gradient(top, #151515, #040404);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));
background-image: -webkit-linear-gradient(top, #151515, #040404);
background-image: -o-linear-gradient(top, #151515, #040404);
background-image: linear-gradient(to bottom, #151515, #040404);
background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);
border-color: #040404 #040404 #000000;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.navbar-inverse .btn-navbar:hover,
-.navbar-inverse .btn-navbar:focus,
-.navbar-inverse .btn-navbar:active,
-.navbar-inverse .btn-navbar.active,
-.navbar-inverse .btn-navbar.disabled,
-.navbar-inverse .btn-navbar[disabled] {
- color: #ffffff;
- background-color: #040404;
- *background-color: #000000;
-}
-
-.navbar-inverse .btn-navbar:active,
-.navbar-inverse .btn-navbar.active {
- background-color: #000000 \9;
+ *background-color: #040404;
+ /* Darken IE7 buttons by default so they stand out more given they won't have borders */
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-
.navbar-inverse .btn-navbar:hover,
.navbar-inverse .btn-navbar:focus,
.navbar-inverse .btn-navbar:active,
@@ -5867,60 +4174,53 @@ input[type="submit"].btn.btn-mini {
background-color: #040404;
*background-color: #000000;
}
-
.navbar-inverse .btn-navbar:active,
.navbar-inverse .btn-navbar.active {
background-color: #000000 \9;
}
-
.breadcrumb {
padding: 8px 15px;
margin: 0 0 20px;
list-style: none;
background-color: #f5f5f5;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.breadcrumb > li {
display: inline-block;
*display: inline;
- text-shadow: 0 1px 0 #ffffff;
+ /* IE7 inline-block hack */
*zoom: 1;
+ text-shadow: 0 1px 0 #ffffff;
}
-
.breadcrumb > li > .divider {
padding: 0 5px;
color: #ccc;
}
-
.breadcrumb > .active {
color: #999999;
}
-
.pagination {
margin: 20px 0;
}
-
.pagination ul {
display: inline-block;
*display: inline;
- margin-bottom: 0;
+ /* IE7 inline-block hack */
+ *zoom: 1;
margin-left: 0;
+ margin-bottom: 0;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- *zoom: 1;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
-
.pagination ul > li {
display: inline;
}
-
.pagination ul > li > a,
.pagination ul > li > span {
float: left;
@@ -5931,153 +4231,123 @@ input[type="submit"].btn.btn-mini {
border: 1px solid #dddddd;
border-left-width: 0;
}
-
.pagination ul > li > a:hover,
.pagination ul > li > a:focus,
.pagination ul > .active > a,
.pagination ul > .active > span {
background-color: #f5f5f5;
}
-
.pagination ul > .active > a,
.pagination ul > .active > span {
color: #999999;
cursor: default;
}
-
.pagination ul > .disabled > span,
.pagination ul > .disabled > a,
.pagination ul > .disabled > a:hover,
.pagination ul > .disabled > a:focus {
color: #999999;
- cursor: default;
background-color: transparent;
+ cursor: default;
}
-
.pagination ul > li:first-child > a,
.pagination ul > li:first-child > span {
border-left-width: 1px;
- -webkit-border-bottom-left-radius: 4px;
- border-bottom-left-radius: 4px;
-webkit-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
- -moz-border-radius-bottomleft: 4px;
-moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
}
-
.pagination ul > li:last-child > a,
.pagination ul > li:last-child > span {
-webkit-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
- -webkit-border-bottom-right-radius: 4px;
- border-bottom-right-radius: 4px;
-moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
-moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
}
-
.pagination-centered {
text-align: center;
}
-
.pagination-right {
text-align: right;
}
-
.pagination-large ul > li > a,
.pagination-large ul > li > span {
padding: 11px 19px;
font-size: 17.5px;
}
-
.pagination-large ul > li:first-child > a,
.pagination-large ul > li:first-child > span {
- -webkit-border-bottom-left-radius: 6px;
- border-bottom-left-radius: 6px;
-webkit-border-top-left-radius: 6px;
- border-top-left-radius: 6px;
- -moz-border-radius-bottomleft: 6px;
-moz-border-radius-topleft: 6px;
+ border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-bottom-left-radius: 6px;
}
-
.pagination-large ul > li:last-child > a,
.pagination-large ul > li:last-child > span {
-webkit-border-top-right-radius: 6px;
- border-top-right-radius: 6px;
- -webkit-border-bottom-right-radius: 6px;
- border-bottom-right-radius: 6px;
-moz-border-radius-topright: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
-moz-border-radius-bottomright: 6px;
+ border-bottom-right-radius: 6px;
}
-
.pagination-mini ul > li:first-child > a,
.pagination-small ul > li:first-child > a,
.pagination-mini ul > li:first-child > span,
.pagination-small ul > li:first-child > span {
- -webkit-border-bottom-left-radius: 3px;
- border-bottom-left-radius: 3px;
-webkit-border-top-left-radius: 3px;
- border-top-left-radius: 3px;
- -moz-border-radius-bottomleft: 3px;
-moz-border-radius-topleft: 3px;
+ border-top-left-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ -moz-border-radius-bottomleft: 3px;
+ border-bottom-left-radius: 3px;
}
-
.pagination-mini ul > li:last-child > a,
.pagination-small ul > li:last-child > a,
.pagination-mini ul > li:last-child > span,
.pagination-small ul > li:last-child > span {
-webkit-border-top-right-radius: 3px;
- border-top-right-radius: 3px;
- -webkit-border-bottom-right-radius: 3px;
- border-bottom-right-radius: 3px;
-moz-border-radius-topright: 3px;
+ border-top-right-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
-moz-border-radius-bottomright: 3px;
+ border-bottom-right-radius: 3px;
}
-
.pagination-small ul > li > a,
.pagination-small ul > li > span {
padding: 2px 10px;
font-size: 11.9px;
}
-
.pagination-mini ul > li > a,
.pagination-mini ul > li > span {
padding: 0 6px;
font-size: 10.5px;
}
-
.pager {
margin: 20px 0;
- text-align: center;
list-style: none;
+ text-align: center;
*zoom: 1;
}
-
.pager:before,
.pager:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.pager:after {
- clear: both;
-}
-
-.pager:before,
-.pager:after {
- display: table;
line-height: 0;
- content: "";
}
-
.pager:after {
clear: both;
}
-
.pager li {
display: inline;
}
-
.pager li > a,
.pager li > span {
display: inline-block;
@@ -6085,35 +4355,30 @@ input[type="submit"].btn.btn-mini {
background-color: #fff;
border: 1px solid #ddd;
-webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
}
-
.pager li > a:hover,
.pager li > a:focus {
text-decoration: none;
background-color: #f5f5f5;
}
-
.pager .next > a,
.pager .next > span {
float: right;
}
-
.pager .previous > a,
.pager .previous > span {
float: left;
}
-
.pager .disabled > a,
.pager .disabled > a:hover,
.pager .disabled > a:focus,
.pager .disabled > span {
color: #999999;
- cursor: default;
background-color: #fff;
+ cursor: default;
}
-
.modal-backdrop {
position: fixed;
top: 0;
@@ -6123,17 +4388,14 @@ input[type="submit"].btn.btn-mini {
z-index: 1040;
background-color: #000000;
}
-
.modal-backdrop.fade {
opacity: 0;
}
-
.modal-backdrop,
.modal-backdrop.fade.in {
opacity: 0.8;
filter: alpha(opacity=80);
}
-
.modal {
position: fixed;
top: 10%;
@@ -6145,55 +4407,48 @@ input[type="submit"].btn.btn-mini {
border: 1px solid #999;
border: 1px solid rgba(0, 0, 0, 0.3);
*border: 1px solid #999;
+ /* IE6-7 */
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- outline: none;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-webkit-background-clip: padding-box;
- -moz-background-clip: padding-box;
- background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+ outline: none;
}
-
.modal.fade {
+ -webkit-transition: opacity .3s linear, top .3s ease-out;
+ -moz-transition: opacity .3s linear, top .3s ease-out;
+ -o-transition: opacity .3s linear, top .3s ease-out;
+ transition: opacity .3s linear, top .3s ease-out;
top: -25%;
- -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
- -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
- -o-transition: opacity 0.3s linear, top 0.3s ease-out;
- transition: opacity 0.3s linear, top 0.3s ease-out;
}
-
.modal.fade.in {
top: 10%;
}
-
.modal-header {
padding: 9px 15px;
border-bottom: 1px solid #eee;
}
-
.modal-header .close {
margin-top: 2px;
}
-
.modal-header h3 {
margin: 0;
line-height: 30px;
}
-
.modal-body {
position: relative;
+ overflow-y: auto;
max-height: 400px;
padding: 15px;
- overflow-y: auto;
}
-
.modal-form {
margin-bottom: 0;
}
-
.modal-footer {
padding: 14px 15px 15px;
margin-bottom: 0;
@@ -6201,85 +4456,62 @@ input[type="submit"].btn.btn-mini {
background-color: #f5f5f5;
border-top: 1px solid #ddd;
-webkit-border-radius: 0 0 6px 6px;
- -moz-border-radius: 0 0 6px 6px;
- border-radius: 0 0 6px 6px;
- *zoom: 1;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
-webkit-box-shadow: inset 0 1px 0 #ffffff;
- -moz-box-shadow: inset 0 1px 0 #ffffff;
- box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+ *zoom: 1;
}
-
.modal-footer:before,
.modal-footer:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.modal-footer:after {
- clear: both;
-}
-
-.modal-footer:before,
-.modal-footer:after {
- display: table;
line-height: 0;
- content: "";
}
-
.modal-footer:after {
clear: both;
}
-
.modal-footer .btn + .btn {
- margin-bottom: 0;
margin-left: 5px;
+ margin-bottom: 0;
}
-
.modal-footer .btn-group .btn + .btn {
margin-left: -1px;
}
-
.modal-footer .btn-block + .btn-block {
margin-left: 0;
}
-
.tooltip {
position: absolute;
z-index: 1030;
display: block;
+ visibility: visible;
font-size: 11px;
line-height: 1.4;
opacity: 0;
filter: alpha(opacity=0);
- visibility: visible;
}
-
.tooltip.in {
opacity: 0.8;
filter: alpha(opacity=80);
}
-
.tooltip.top {
- padding: 5px 0;
margin-top: -3px;
+ padding: 5px 0;
}
-
.tooltip.right {
- padding: 0 5px;
margin-left: 3px;
+ padding: 0 5px;
}
-
.tooltip.bottom {
- padding: 5px 0;
margin-top: 3px;
+ padding: 5px 0;
}
-
.tooltip.left {
- padding: 0 5px;
margin-left: -3px;
+ padding: 0 5px;
}
-
.tooltip-inner {
max-width: 200px;
padding: 8px;
@@ -6288,10 +4520,9 @@ input[type="submit"].btn.btn-mini {
text-decoration: none;
background-color: #000000;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.tooltip-arrow {
position: absolute;
width: 0;
@@ -6299,39 +4530,34 @@ input[type="submit"].btn.btn-mini {
border-color: transparent;
border-style: solid;
}
-
.tooltip.top .tooltip-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
- border-top-color: #000000;
border-width: 5px 5px 0;
+ border-top-color: #000000;
}
-
.tooltip.right .tooltip-arrow {
top: 50%;
left: 0;
margin-top: -5px;
- border-right-color: #000000;
border-width: 5px 5px 5px 0;
+ border-right-color: #000000;
}
-
.tooltip.left .tooltip-arrow {
top: 50%;
right: 0;
margin-top: -5px;
- border-left-color: #000000;
border-width: 5px 0 5px 5px;
+ border-left-color: #000000;
}
-
.tooltip.bottom .tooltip-arrow {
top: 0;
left: 50%;
margin-left: -5px;
- border-bottom-color: #000000;
border-width: 0 5px 5px;
+ border-bottom-color: #000000;
}
-
.popover {
position: absolute;
top: 0;
@@ -6341,58 +4567,50 @@ input[type="submit"].btn.btn-mini {
max-width: 276px;
padding: 1px;
text-align: left;
- white-space: normal;
background-color: #ffffff;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding;
- background-clip: padding-box;
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ white-space: normal;
}
-
.popover.top {
margin-top: -10px;
}
-
.popover.right {
margin-left: 10px;
}
-
.popover.bottom {
margin-top: 10px;
}
-
.popover.left {
margin-left: -10px;
}
-
.popover-title {
- padding: 8px 14px;
margin: 0;
+ padding: 8px 14px;
font-size: 14px;
font-weight: normal;
line-height: 18px;
background-color: #f7f7f7;
border-bottom: 1px solid #ebebeb;
-webkit-border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- border-radius: 5px 5px 0 0;
+ -moz-border-radius: 5px 5px 0 0;
+ border-radius: 5px 5px 0 0;
}
-
.popover-title:empty {
display: none;
}
-
.popover-content {
padding: 9px 14px;
}
-
.popover .arrow,
.popover .arrow:after {
position: absolute;
@@ -6402,192 +4620,153 @@ input[type="submit"].btn.btn-mini {
border-color: transparent;
border-style: solid;
}
-
.popover .arrow {
border-width: 11px;
}
-
.popover .arrow:after {
border-width: 10px;
content: "";
}
-
.popover.top .arrow {
- bottom: -11px;
left: 50%;
margin-left: -11px;
+ border-bottom-width: 0;
border-top-color: #999;
border-top-color: rgba(0, 0, 0, 0.25);
- border-bottom-width: 0;
+ bottom: -11px;
}
-
.popover.top .arrow:after {
bottom: 1px;
margin-left: -10px;
- border-top-color: #ffffff;
border-bottom-width: 0;
+ border-top-color: #ffffff;
}
-
.popover.right .arrow {
top: 50%;
left: -11px;
margin-top: -11px;
+ border-left-width: 0;
border-right-color: #999;
border-right-color: rgba(0, 0, 0, 0.25);
- border-left-width: 0;
}
-
.popover.right .arrow:after {
- bottom: -10px;
left: 1px;
- border-right-color: #ffffff;
+ bottom: -10px;
border-left-width: 0;
+ border-right-color: #ffffff;
}
-
.popover.bottom .arrow {
- top: -11px;
left: 50%;
margin-left: -11px;
+ border-top-width: 0;
border-bottom-color: #999;
border-bottom-color: rgba(0, 0, 0, 0.25);
- border-top-width: 0;
+ top: -11px;
}
-
.popover.bottom .arrow:after {
top: 1px;
margin-left: -10px;
- border-bottom-color: #ffffff;
border-top-width: 0;
+ border-bottom-color: #ffffff;
}
-
.popover.left .arrow {
top: 50%;
right: -11px;
margin-top: -11px;
+ border-right-width: 0;
border-left-color: #999;
border-left-color: rgba(0, 0, 0, 0.25);
- border-right-width: 0;
}
-
.popover.left .arrow:after {
right: 1px;
- bottom: -10px;
- border-left-color: #ffffff;
border-right-width: 0;
+ border-left-color: #ffffff;
+ bottom: -10px;
}
-
.thumbnails {
margin-left: -20px;
list-style: none;
*zoom: 1;
}
-
.thumbnails:before,
.thumbnails:after {
display: table;
- line-height: 0;
content: "";
-}
-
-.thumbnails:after {
- clear: both;
-}
-
-.thumbnails:before,
-.thumbnails:after {
- display: table;
line-height: 0;
- content: "";
}
-
.thumbnails:after {
clear: both;
}
-
.row-fluid .thumbnails {
margin-left: 0;
}
-
.thumbnails > li {
float: left;
margin-bottom: 20px;
margin-left: 20px;
}
-
.thumbnail {
display: block;
padding: 4px;
line-height: 20px;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
- -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
-webkit-transition: all 0.2s ease-in-out;
- -moz-transition: all 0.2s ease-in-out;
- -o-transition: all 0.2s ease-in-out;
- transition: all 0.2s ease-in-out;
+ -moz-transition: all 0.2s ease-in-out;
+ -o-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
}
-
a.thumbnail:hover,
a.thumbnail:focus {
border-color: #0088cc;
-webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
- -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
- box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
}
-
.thumbnail > img {
display: block;
max-width: 100%;
- margin-right: auto;
margin-left: auto;
+ margin-right: auto;
}
-
.thumbnail .caption {
padding: 9px;
color: #555555;
}
-
.media,
.media-body {
overflow: hidden;
*overflow: visible;
zoom: 1;
}
-
.media,
.media .media {
margin-top: 15px;
}
-
.media:first-child {
margin-top: 0;
}
-
.media-object {
display: block;
}
-
.media-heading {
margin: 0 0 5px;
}
-
.media > .pull-left {
margin-right: 10px;
}
-
.media > .pull-right {
margin-left: 10px;
}
-
.media-list {
margin-left: 0;
list-style: none;
}
-
.label,
.badge {
display: inline-block;
@@ -6596,31 +4775,27 @@ a.thumbnail:focus {
font-weight: bold;
line-height: 14px;
color: #ffffff;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- white-space: nowrap;
vertical-align: baseline;
+ white-space: nowrap;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #999999;
}
-
.label {
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
-
.badge {
- padding-right: 9px;
padding-left: 9px;
+ padding-right: 9px;
-webkit-border-radius: 9px;
- -moz-border-radius: 9px;
- border-radius: 9px;
+ -moz-border-radius: 9px;
+ border-radius: 9px;
}
-
.label:empty,
.badge:empty {
display: none;
}
-
a.label:hover,
a.label:focus,
a.badge:hover,
@@ -6629,68 +4804,55 @@ a.badge:focus {
text-decoration: none;
cursor: pointer;
}
-
.label-important,
.badge-important {
background-color: #b94a48;
}
-
.label-important[href],
.badge-important[href] {
background-color: #953b39;
}
-
.label-warning,
.badge-warning {
background-color: #f89406;
}
-
.label-warning[href],
.badge-warning[href] {
background-color: #c67605;
}
-
.label-success,
.badge-success {
background-color: #468847;
}
-
.label-success[href],
.badge-success[href] {
background-color: #356635;
}
-
.label-info,
.badge-info {
background-color: #3a87ad;
}
-
.label-info[href],
.badge-info[href] {
background-color: #2d6987;
}
-
.label-inverse,
.badge-inverse {
background-color: #333333;
}
-
.label-inverse[href],
.badge-inverse[href] {
background-color: #1a1a1a;
}
-
.btn .label,
.btn .badge {
position: relative;
top: -1px;
}
-
.btn-mini .label,
.btn-mini .badge {
top: 0;
}
-
@-webkit-keyframes progress-bar-stripes {
from {
background-position: 40px 0;
@@ -6699,7 +4861,6 @@ a.badge:focus {
background-position: 0 0;
}
}
-
@-moz-keyframes progress-bar-stripes {
from {
background-position: 40px 0;
@@ -6708,7 +4869,6 @@ a.badge:focus {
background-position: 0 0;
}
}
-
@-ms-keyframes progress-bar-stripes {
from {
background-position: 40px 0;
@@ -6717,7 +4877,6 @@ a.badge:focus {
background-position: 0 0;
}
}
-
@-o-keyframes progress-bar-stripes {
from {
background-position: 0 0;
@@ -6726,7 +4885,6 @@ a.badge:focus {
background-position: 40px 0;
}
}
-
@keyframes progress-bar-stripes {
from {
background-position: 40px 0;
@@ -6735,11 +4893,10 @@ a.badge:focus {
background-position: 0 0;
}
}
-
.progress {
+ overflow: hidden;
height: 20px;
margin-bottom: 20px;
- overflow: hidden;
background-color: #f7f7f7;
background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
@@ -6747,21 +4904,20 @@ a.badge:focus {
background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
background-repeat: repeat-x;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.progress .bar {
- float: left;
- width: 0;
+ width: 0%;
height: 100%;
- font-size: 12px;
color: #ffffff;
+ float: left;
+ font-size: 12px;
text-align: center;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #0e90d2;
@@ -6773,23 +4929,21 @@ a.badge:focus {
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
-webkit-transition: width 0.6s ease;
- -moz-transition: width 0.6s ease;
- -o-transition: width 0.6s ease;
- transition: width 0.6s ease;
+ -moz-transition: width 0.6s ease;
+ -o-transition: width 0.6s ease;
+ transition: width 0.6s ease;
}
-
.progress .bar + .bar {
- -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
+ -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
+ box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);
}
-
.progress-striped .bar {
background-color: #149bdf;
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
@@ -6798,19 +4952,17 @@ a.badge:focus {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-webkit-background-size: 40px 40px;
- -moz-background-size: 40px 40px;
- -o-background-size: 40px 40px;
- background-size: 40px 40px;
+ -moz-background-size: 40px 40px;
+ -o-background-size: 40px 40px;
+ background-size: 40px 40px;
}
-
.progress.active .bar {
-webkit-animation: progress-bar-stripes 2s linear infinite;
- -moz-animation: progress-bar-stripes 2s linear infinite;
- -ms-animation: progress-bar-stripes 2s linear infinite;
- -o-animation: progress-bar-stripes 2s linear infinite;
- animation: progress-bar-stripes 2s linear infinite;
+ -moz-animation: progress-bar-stripes 2s linear infinite;
+ -ms-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
}
-
.progress-danger .bar,
.progress .bar-danger {
background-color: #dd514c;
@@ -6822,7 +4974,6 @@ a.badge:focus {
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);
}
-
.progress-danger.progress-striped .bar,
.progress-striped .bar-danger {
background-color: #ee5f5b;
@@ -6832,7 +4983,6 @@ a.badge:focus {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
-
.progress-success .bar,
.progress .bar-success {
background-color: #5eb95e;
@@ -6844,7 +4994,6 @@ a.badge:focus {
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);
}
-
.progress-success.progress-striped .bar,
.progress-striped .bar-success {
background-color: #62c462;
@@ -6854,7 +5003,6 @@ a.badge:focus {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
-
.progress-info .bar,
.progress .bar-info {
background-color: #4bb1cf;
@@ -6866,7 +5014,6 @@ a.badge:focus {
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);
}
-
.progress-info.progress-striped .bar,
.progress-striped .bar-info {
background-color: #5bc0de;
@@ -6876,7 +5023,6 @@ a.badge:focus {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
-
.progress-warning .bar,
.progress .bar-warning {
background-color: #faa732;
@@ -6888,7 +5034,6 @@ a.badge:focus {
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
}
-
.progress-warning.progress-striped .bar,
.progress-striped .bar-warning {
background-color: #fbb450;
@@ -6898,102 +5043,83 @@ a.badge:focus {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
-
.accordion {
margin-bottom: 20px;
}
-
.accordion-group {
margin-bottom: 2px;
border: 1px solid #e5e5e5;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
.accordion-heading {
border-bottom: 0;
}
-
.accordion-heading .accordion-toggle {
display: block;
padding: 8px 15px;
}
-
.accordion-toggle {
cursor: pointer;
}
-
.accordion-inner {
padding: 9px 15px;
border-top: 1px solid #e5e5e5;
}
-
.carousel {
position: relative;
margin-bottom: 20px;
line-height: 1;
}
-
.carousel-inner {
- position: relative;
- width: 100%;
overflow: hidden;
+ width: 100%;
+ position: relative;
}
-
.carousel-inner > .item {
- position: relative;
display: none;
+ position: relative;
-webkit-transition: 0.6s ease-in-out left;
- -moz-transition: 0.6s ease-in-out left;
- -o-transition: 0.6s ease-in-out left;
- transition: 0.6s ease-in-out left;
+ -moz-transition: 0.6s ease-in-out left;
+ -o-transition: 0.6s ease-in-out left;
+ transition: 0.6s ease-in-out left;
}
-
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
display: block;
line-height: 1;
}
-
.carousel-inner > .active,
.carousel-inner > .next,
.carousel-inner > .prev {
display: block;
}
-
.carousel-inner > .active {
left: 0;
}
-
.carousel-inner > .next,
.carousel-inner > .prev {
position: absolute;
top: 0;
width: 100%;
}
-
.carousel-inner > .next {
left: 100%;
}
-
.carousel-inner > .prev {
left: -100%;
}
-
.carousel-inner > .next.left,
.carousel-inner > .prev.right {
left: 0;
}
-
.carousel-inner > .active.left {
left: -100%;
}
-
.carousel-inner > .active.right {
left: 100%;
}
-
.carousel-control {
position: absolute;
top: 40%;
@@ -7009,17 +5135,15 @@ a.badge:focus {
background: #222222;
border: 3px solid #ffffff;
-webkit-border-radius: 23px;
- -moz-border-radius: 23px;
- border-radius: 23px;
+ -moz-border-radius: 23px;
+ border-radius: 23px;
opacity: 0.5;
filter: alpha(opacity=50);
}
-
.carousel-control.right {
- right: 15px;
left: auto;
+ right: 15px;
}
-
.carousel-control:hover,
.carousel-control:focus {
color: #ffffff;
@@ -7027,7 +5151,6 @@ a.badge:focus {
opacity: 0.9;
filter: alpha(opacity=90);
}
-
.carousel-indicators {
position: absolute;
top: 15px;
@@ -7036,7 +5159,6 @@ a.badge:focus {
margin: 0;
list-style: none;
}
-
.carousel-indicators li {
display: block;
float: left;
@@ -7048,35 +5170,29 @@ a.badge:focus {
background-color: rgba(255, 255, 255, 0.25);
border-radius: 5px;
}
-
.carousel-indicators .active {
background-color: #fff;
}
-
.carousel-caption {
position: absolute;
+ left: 0;
right: 0;
bottom: 0;
- left: 0;
padding: 15px;
background: #333333;
background: rgba(0, 0, 0, 0.75);
}
-
.carousel-caption h4,
.carousel-caption p {
- line-height: 20px;
color: #ffffff;
+ line-height: 20px;
}
-
.carousel-caption h4 {
margin: 0 0 5px;
}
-
.carousel-caption p {
margin-bottom: 0;
}
-
.hero-unit {
padding: 60px;
margin-bottom: 30px;
@@ -7086,46 +5202,235 @@ a.badge:focus {
color: inherit;
background-color: #eeeeee;
-webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
}
-
.hero-unit h1 {
margin-bottom: 0;
font-size: 60px;
line-height: 1;
- letter-spacing: -1px;
color: inherit;
+ letter-spacing: -1px;
}
-
.hero-unit li {
line-height: 30px;
}
-
.pull-right {
float: right;
}
-
.pull-left {
float: left;
}
-
.hide {
display: none;
}
-
.show {
display: block;
}
-
.invisible {
visibility: hidden;
}
-
.affix {
position: fixed;
}
-
+.list-item {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.list-item blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.list-header,
+.edit-header {
+ position: fixed;
+ width: 100%;
+ margin-top: 11px;
+ z-index: 1;
+ background-color: #ffffff;
+}
+.list-body {
+ padding-top: 100px;
+}
+.edit-header {
+ padding-top: 10px;
+}
+.edit-body {
+ padding-top: 100px;
+}
+.page-header {
+ padding-left: 20px;
+ z-index: 2;
+}
+.header-rhs {
+ min-width: 226px;
+ min-height: 40px;
+ padding-right: 20px;
+ padding-bottom: 5px;
+ display: block;
+}
+.list-header .header-rhs {
+ margin: 15px 0;
+}
+.fixed-header {
+ position: fixed;
+ width: 100%;
+ margin-top: 11px;
+ z-index: 1;
+}
+.gridStyle {
+ border: 1px solid #d4d4d4;
+ margin: auto;
+ height: 400px;
+}
+.gridStyle .ngTopPanel {
+ background-color: #ffffff;
+}
+.gridStyle .ngHeaderCell {
+ background-color: #e4e4e4;
+}
+.gridStyle .fng-right {
+ text-align: right;
+}
+.gridStyle .fng-left {
+ text-align: left;
+}
+.gridStyle .fng-centre,
+.gridStyle .fng-center {
+ text-align: center;
+}
+.gridStyle .ngTotalCell {
+ font-weight: bold;
+}
+button.form-btn {
+ width: 8em;
+ height: 2em;
+}
+.form-btn-grp {
+ max-width: 17em;
+}
+form.form-horizontal.compact input + .help-block,
+form.form-horizontal.compact select + .help-block,
+form.form-horizontal.compact textarea + .help-block,
+form.form-horizontal.compact .uneditable-input + .help-block,
+form.form-horizontal.compact .input-prepend + .help-block,
+form.form-horizontal.compact .input-append + .help-block {
+ margin-top: 0;
+ margin-bottom: 2px;
+}
+form.form-horizontal.compact hr {
+ margin: 8px 0;
+}
+form .schema-head,
+form .sub-doc,
+form .schema-foot {
+ min-height: 20px;
+ margin-bottom: 20px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+form .schema-head blockquote,
+form .sub-doc blockquote,
+form .schema-foot blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+form .schema-head {
+ margin-top: 8px;
+ margin-bottom: 5px;
+ border: 1px solid #ddd;
+ padding: 4px 180px;
+}
+form .sub-doc {
+ padding: 5px 5px 2px 0;
+ width: 97%;
+ margin-bottom: 3px;
+ position: relative;
+}
+form .sub-doc-btns {
+ position: absolute;
+ right: 8px;
+}
+form .schema-foot {
+ padding: 5px 180px;
+ margin: 5px 0;
+}
+form input[type="checkbox"].ng-invalid-required:before,
+form span:first-child input[type="radio"].ng-invalid-required:before {
+ content: "*";
+ font-weight: bold;
+ color: red;
+ margin-left: -8px;
+}
+form input.ng-invalid-required,
+form select.fng-invalid-required,
+form select.ng-invalid-required,
+form textarea.ng-invalid-required {
+ background-color: rgba(255, 0, 0, 0.1);
+}
+form option {
+ background-color: white;
+}
+form .fng-select2 {
+ width: 220px;
+}
+form .form-inline > .sub-doc {
+ padding: 0 5px;
+ border: none;
+ box-shadow: none;
+}
+a.fng-link,
+span.fng-link {
+ line-height: 30px;
+}
+.form-inline a.fng-link,
+.form-inline span.fng-link {
+ padding: 0 15px;
+}
+span input[type="radio"] {
+ margin: 9px 0 0;
+}
+.global-search {
+ position: relative;
+ float: right;
+}
+.results-container {
+ width: 6000px;
+ z-index: 3;
+ position: absolute;
+ top: 41px;
+ right: 0;
+}
+.search-results {
+ float: right;
+ border: 1px solid gray;
+ -webkit-box-shadow: 10px 10px 10px #888;
+ box-shadow: 10px 10px 10px #888;
+ background: white;
+ padding: 5px;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+.search-results .search-result.focus {
+ color: white;
+}
+.dropdown-menu > .disabled > li,
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ cursor: not-allowed;
+}
/*!
* Bootstrap Responsive v2.3.2
*
@@ -7135,64 +5440,25 @@ a.badge:focus {
*
* Designed and built with all the love in the world by @mdo and @fat.
*/
-
-.clearfix {
- *zoom: 1;
-}
-
-.clearfix:before,
-.clearfix:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.clearfix:after {
- clear: both;
-}
-
-.hide-text {
- font: 0/0 a;
- color: transparent;
- text-shadow: none;
- background-color: transparent;
- border: 0;
-}
-
-.input-block-level {
- display: block;
- width: 100%;
- min-height: 30px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
@-ms-viewport {
width: device-width;
}
-
.hidden {
display: none;
visibility: hidden;
}
-
.visible-phone {
display: none !important;
}
-
.visible-tablet {
display: none !important;
}
-
.hidden-desktop {
display: none !important;
}
-
.visible-desktop {
display: inherit !important;
}
-
@media (min-width: 768px) and (max-width: 979px) {
.hidden-desktop {
display: inherit !important;
@@ -7207,7 +5473,6 @@ a.badge:focus {
display: none !important;
}
}
-
@media (max-width: 767px) {
.hidden-desktop {
display: inherit !important;
@@ -7222,11 +5487,9 @@ a.badge:focus {
display: none !important;
}
}
-
.visible-print {
display: none !important;
}
-
@media print {
.visible-print {
display: inherit !important;
@@ -7235,7 +5498,6 @@ a.badge:focus {
display: none !important;
}
}
-
@media (min-width: 1200px) {
.row {
margin-left: -30px;
@@ -7244,17 +5506,8 @@ a.badge:focus {
.row:before,
.row:after {
display: table;
- line-height: 0;
content: "";
- }
- .row:after {
- clear: both;
- }
- .row:before,
- .row:after {
- display: table;
line-height: 0;
- content: "";
}
.row:after {
clear: both;
@@ -7342,476 +5595,179 @@ a.badge:focus {
.offset1 {
margin-left: 130px;
}
- .row {
- margin-left: -30px;
+ .row-fluid {
+ width: 100%;
*zoom: 1;
}
- .row:before,
- .row:after {
+ .row-fluid:before,
+ .row-fluid:after {
display: table;
- line-height: 0;
content: "";
- }
- .row:after {
- clear: both;
- }
- .row:before,
- .row:after {
- display: table;
line-height: 0;
- content: "";
}
- .row:after {
+ .row-fluid:after {
clear: both;
}
- [class*="span"] {
+ .row-fluid [class*="span"] {
+ display: block;
+ width: 100%;
+ min-height: 30px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
float: left;
- min-height: 1px;
- margin-left: 30px;
+ margin-left: 2.56410256%;
+ *margin-left: 2.51091107%;
}
- .container,
- .navbar-static-top .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 1170px;
+ .row-fluid [class*="span"]:first-child {
+ margin-left: 0;
}
- .span12 {
- width: 1170px;
- }
- .span11 {
- width: 1070px;
- }
- .span10 {
- width: 970px;
- }
- .span9 {
- width: 870px;
- }
- .span8 {
- width: 770px;
- }
- .span7 {
- width: 670px;
- }
- .span6 {
- width: 570px;
- }
- .span5 {
- width: 470px;
- }
- .span4 {
- width: 370px;
- }
- .span3 {
- width: 270px;
- }
- .span2 {
- width: 170px;
- }
- .span1 {
- width: 70px;
- }
- .offset12 {
- margin-left: 1230px;
- }
- .offset11 {
- margin-left: 1130px;
- }
- .offset10 {
- margin-left: 1030px;
- }
- .offset9 {
- margin-left: 930px;
- }
- .offset8 {
- margin-left: 830px;
- }
- .offset7 {
- margin-left: 730px;
- }
- .offset6 {
- margin-left: 630px;
- }
- .offset5 {
- margin-left: 530px;
- }
- .offset4 {
- margin-left: 430px;
- }
- .offset3 {
- margin-left: 330px;
- }
- .offset2 {
- margin-left: 230px;
- }
- .offset1 {
- margin-left: 130px;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid [class*="span"] {
- display: block;
- float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.564102564102564%;
- *margin-left: 2.5109110747408616%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.564102564102564%;
+ .row-fluid .controls-row [class*="span"] + [class*="span"] {
+ margin-left: 2.56410256%;
}
.row-fluid .span12 {
width: 100%;
- *width: 99.94680851063829%;
+ *width: 99.94680851%;
}
.row-fluid .span11 {
- width: 91.45299145299145%;
- *width: 91.39979996362975%;
+ width: 91.45299145%;
+ *width: 91.39979996%;
}
.row-fluid .span10 {
- width: 82.90598290598291%;
- *width: 82.8527914166212%;
+ width: 82.90598291%;
+ *width: 82.85279142%;
}
.row-fluid .span9 {
- width: 74.35897435897436%;
- *width: 74.30578286961266%;
+ width: 74.35897436%;
+ *width: 74.30578287%;
}
.row-fluid .span8 {
- width: 65.81196581196582%;
- *width: 65.75877432260411%;
+ width: 65.81196581%;
+ *width: 65.75877432%;
}
.row-fluid .span7 {
- width: 57.26495726495726%;
- *width: 57.21176577559556%;
+ width: 57.26495726%;
+ *width: 57.21176578%;
}
.row-fluid .span6 {
- width: 48.717948717948715%;
- *width: 48.664757228587014%;
+ width: 48.71794872%;
+ *width: 48.66475723%;
}
.row-fluid .span5 {
- width: 40.17094017094017%;
- *width: 40.11774868157847%;
+ width: 40.17094017%;
+ *width: 40.11774868%;
}
.row-fluid .span4 {
- width: 31.623931623931625%;
- *width: 31.570740134569924%;
+ width: 31.62393162%;
+ *width: 31.57074013%;
}
.row-fluid .span3 {
- width: 23.076923076923077%;
- *width: 23.023731587561375%;
+ width: 23.07692308%;
+ *width: 23.02373159%;
}
.row-fluid .span2 {
- width: 14.52991452991453%;
- *width: 14.476723040552828%;
+ width: 14.52991453%;
+ *width: 14.47672304%;
}
.row-fluid .span1 {
- width: 5.982905982905983%;
- *width: 5.929714493544281%;
+ width: 5.98290598%;
+ *width: 5.92971449%;
}
.row-fluid .offset12 {
- margin-left: 105.12820512820512%;
- *margin-left: 105.02182214948171%;
+ margin-left: 105.12820513%;
+ *margin-left: 105.02182215%;
}
.row-fluid .offset12:first-child {
- margin-left: 102.56410256410257%;
- *margin-left: 102.45771958537915%;
+ margin-left: 102.56410256%;
+ *margin-left: 102.45771959%;
}
.row-fluid .offset11 {
- margin-left: 96.58119658119658%;
- *margin-left: 96.47481360247316%;
+ margin-left: 96.58119658%;
+ *margin-left: 96.4748136%;
}
.row-fluid .offset11:first-child {
- margin-left: 94.01709401709402%;
- *margin-left: 93.91071103837061%;
+ margin-left: 94.01709402%;
+ *margin-left: 93.91071104%;
}
.row-fluid .offset10 {
- margin-left: 88.03418803418803%;
- *margin-left: 87.92780505546462%;
+ margin-left: 88.03418803%;
+ *margin-left: 87.92780506%;
}
.row-fluid .offset10:first-child {
- margin-left: 85.47008547008548%;
- *margin-left: 85.36370249136206%;
+ margin-left: 85.47008547%;
+ *margin-left: 85.36370249%;
}
.row-fluid .offset9 {
- margin-left: 79.48717948717949%;
- *margin-left: 79.38079650845607%;
+ margin-left: 79.48717949%;
+ *margin-left: 79.38079651%;
}
.row-fluid .offset9:first-child {
- margin-left: 76.92307692307693%;
- *margin-left: 76.81669394435352%;
+ margin-left: 76.92307692%;
+ *margin-left: 76.81669394%;
}
.row-fluid .offset8 {
- margin-left: 70.94017094017094%;
- *margin-left: 70.83378796144753%;
+ margin-left: 70.94017094%;
+ *margin-left: 70.83378796%;
}
.row-fluid .offset8:first-child {
- margin-left: 68.37606837606839%;
- *margin-left: 68.26968539734497%;
+ margin-left: 68.37606838%;
+ *margin-left: 68.2696854%;
}
.row-fluid .offset7 {
- margin-left: 62.393162393162385%;
- *margin-left: 62.28677941443899%;
+ margin-left: 62.39316239%;
+ *margin-left: 62.28677941%;
}
.row-fluid .offset7:first-child {
- margin-left: 59.82905982905982%;
- *margin-left: 59.72267685033642%;
+ margin-left: 59.82905983%;
+ *margin-left: 59.72267685%;
}
.row-fluid .offset6 {
- margin-left: 53.84615384615384%;
- *margin-left: 53.739770867430444%;
+ margin-left: 53.84615385%;
+ *margin-left: 53.73977087%;
}
.row-fluid .offset6:first-child {
- margin-left: 51.28205128205128%;
- *margin-left: 51.175668303327875%;
+ margin-left: 51.28205128%;
+ *margin-left: 51.1756683%;
}
.row-fluid .offset5 {
- margin-left: 45.299145299145295%;
- *margin-left: 45.1927623204219%;
+ margin-left: 45.2991453%;
+ *margin-left: 45.19276232%;
}
.row-fluid .offset5:first-child {
- margin-left: 42.73504273504273%;
- *margin-left: 42.62865975631933%;
+ margin-left: 42.73504274%;
+ *margin-left: 42.62865976%;
}
.row-fluid .offset4 {
- margin-left: 36.75213675213675%;
- *margin-left: 36.645753773413354%;
+ margin-left: 36.75213675%;
+ *margin-left: 36.64575377%;
}
.row-fluid .offset4:first-child {
- margin-left: 34.18803418803419%;
- *margin-left: 34.081651209310785%;
+ margin-left: 34.18803419%;
+ *margin-left: 34.08165121%;
}
.row-fluid .offset3 {
- margin-left: 28.205128205128204%;
- *margin-left: 28.0987452264048%;
+ margin-left: 28.20512821%;
+ *margin-left: 28.09874523%;
}
.row-fluid .offset3:first-child {
- margin-left: 25.641025641025642%;
- *margin-left: 25.53464266230224%;
+ margin-left: 25.64102564%;
+ *margin-left: 25.53464266%;
}
.row-fluid .offset2 {
- margin-left: 19.65811965811966%;
- *margin-left: 19.551736679396257%;
+ margin-left: 19.65811966%;
+ *margin-left: 19.55173668%;
}
.row-fluid .offset2:first-child {
- margin-left: 17.094017094017094%;
- *margin-left: 16.98763411529369%;
+ margin-left: 17.09401709%;
+ *margin-left: 16.98763412%;
}
.row-fluid .offset1 {
- margin-left: 11.11111111111111%;
- *margin-left: 11.004728132387708%;
+ margin-left: 11.11111111%;
+ *margin-left: 11.00472813%;
}
.row-fluid .offset1:first-child {
- margin-left: 8.547008547008547%;
- *margin-left: 8.440625568285142%;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid [class*="span"] {
- display: block;
- float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.564102564102564%;
- *margin-left: 2.5109110747408616%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.564102564102564%;
- }
- .row-fluid .span12 {
- width: 100%;
- *width: 99.94680851063829%;
- }
- .row-fluid .span11 {
- width: 91.45299145299145%;
- *width: 91.39979996362975%;
- }
- .row-fluid .span10 {
- width: 82.90598290598291%;
- *width: 82.8527914166212%;
- }
- .row-fluid .span9 {
- width: 74.35897435897436%;
- *width: 74.30578286961266%;
- }
- .row-fluid .span8 {
- width: 65.81196581196582%;
- *width: 65.75877432260411%;
- }
- .row-fluid .span7 {
- width: 57.26495726495726%;
- *width: 57.21176577559556%;
- }
- .row-fluid .span6 {
- width: 48.717948717948715%;
- *width: 48.664757228587014%;
- }
- .row-fluid .span5 {
- width: 40.17094017094017%;
- *width: 40.11774868157847%;
- }
- .row-fluid .span4 {
- width: 31.623931623931625%;
- *width: 31.570740134569924%;
- }
- .row-fluid .span3 {
- width: 23.076923076923077%;
- *width: 23.023731587561375%;
- }
- .row-fluid .span2 {
- width: 14.52991452991453%;
- *width: 14.476723040552828%;
- }
- .row-fluid .span1 {
- width: 5.982905982905983%;
- *width: 5.929714493544281%;
- }
- .row-fluid .offset12 {
- margin-left: 105.12820512820512%;
- *margin-left: 105.02182214948171%;
- }
- .row-fluid .offset12:first-child {
- margin-left: 102.56410256410257%;
- *margin-left: 102.45771958537915%;
- }
- .row-fluid .offset11 {
- margin-left: 96.58119658119658%;
- *margin-left: 96.47481360247316%;
- }
- .row-fluid .offset11:first-child {
- margin-left: 94.01709401709402%;
- *margin-left: 93.91071103837061%;
- }
- .row-fluid .offset10 {
- margin-left: 88.03418803418803%;
- *margin-left: 87.92780505546462%;
- }
- .row-fluid .offset10:first-child {
- margin-left: 85.47008547008548%;
- *margin-left: 85.36370249136206%;
- }
- .row-fluid .offset9 {
- margin-left: 79.48717948717949%;
- *margin-left: 79.38079650845607%;
- }
- .row-fluid .offset9:first-child {
- margin-left: 76.92307692307693%;
- *margin-left: 76.81669394435352%;
- }
- .row-fluid .offset8 {
- margin-left: 70.94017094017094%;
- *margin-left: 70.83378796144753%;
- }
- .row-fluid .offset8:first-child {
- margin-left: 68.37606837606839%;
- *margin-left: 68.26968539734497%;
- }
- .row-fluid .offset7 {
- margin-left: 62.393162393162385%;
- *margin-left: 62.28677941443899%;
- }
- .row-fluid .offset7:first-child {
- margin-left: 59.82905982905982%;
- *margin-left: 59.72267685033642%;
- }
- .row-fluid .offset6 {
- margin-left: 53.84615384615384%;
- *margin-left: 53.739770867430444%;
- }
- .row-fluid .offset6:first-child {
- margin-left: 51.28205128205128%;
- *margin-left: 51.175668303327875%;
- }
- .row-fluid .offset5 {
- margin-left: 45.299145299145295%;
- *margin-left: 45.1927623204219%;
- }
- .row-fluid .offset5:first-child {
- margin-left: 42.73504273504273%;
- *margin-left: 42.62865975631933%;
- }
- .row-fluid .offset4 {
- margin-left: 36.75213675213675%;
- *margin-left: 36.645753773413354%;
- }
- .row-fluid .offset4:first-child {
- margin-left: 34.18803418803419%;
- *margin-left: 34.081651209310785%;
- }
- .row-fluid .offset3 {
- margin-left: 28.205128205128204%;
- *margin-left: 28.0987452264048%;
- }
- .row-fluid .offset3:first-child {
- margin-left: 25.641025641025642%;
- *margin-left: 25.53464266230224%;
- }
- .row-fluid .offset2 {
- margin-left: 19.65811965811966%;
- *margin-left: 19.551736679396257%;
- }
- .row-fluid .offset2:first-child {
- margin-left: 17.094017094017094%;
- *margin-left: 16.98763411529369%;
- }
- .row-fluid .offset1 {
- margin-left: 11.11111111111111%;
- *margin-left: 11.004728132387708%;
- }
- .row-fluid .offset1:first-child {
- margin-left: 8.547008547008547%;
- *margin-left: 8.440625568285142%;
+ margin-left: 8.54700855%;
+ *margin-left: 8.44062557%;
}
input,
textarea,
@@ -7829,243 +5785,69 @@ a.badge:focus {
input.span11,
textarea.span11,
.uneditable-input.span11 {
- width: 1056px;
- }
- input.span10,
- textarea.span10,
- .uneditable-input.span10 {
- width: 956px;
- }
- input.span9,
- textarea.span9,
- .uneditable-input.span9 {
- width: 856px;
- }
- input.span8,
- textarea.span8,
- .uneditable-input.span8 {
- width: 756px;
- }
- input.span7,
- textarea.span7,
- .uneditable-input.span7 {
- width: 656px;
- }
- input.span6,
- textarea.span6,
- .uneditable-input.span6 {
- width: 556px;
- }
- input.span5,
- textarea.span5,
- .uneditable-input.span5 {
- width: 456px;
- }
- input.span4,
- textarea.span4,
- .uneditable-input.span4 {
- width: 356px;
- }
- input.span3,
- textarea.span3,
- .uneditable-input.span3 {
- width: 256px;
- }
- input.span2,
- textarea.span2,
- .uneditable-input.span2 {
- width: 156px;
- }
- input.span1,
- textarea.span1,
- .uneditable-input.span1 {
- width: 56px;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- .controls-row [class*="span"] + [class*="span"] {
- margin-left: 30px;
- }
- input.span12,
- textarea.span12,
- .uneditable-input.span12 {
- width: 1156px;
- }
- input.span11,
- textarea.span11,
- .uneditable-input.span11 {
- width: 1056px;
- }
- input.span10,
- textarea.span10,
- .uneditable-input.span10 {
- width: 956px;
- }
- input.span9,
- textarea.span9,
- .uneditable-input.span9 {
- width: 856px;
- }
- input.span8,
- textarea.span8,
- .uneditable-input.span8 {
- width: 756px;
- }
- input.span7,
- textarea.span7,
- .uneditable-input.span7 {
- width: 656px;
- }
- input.span6,
- textarea.span6,
- .uneditable-input.span6 {
- width: 556px;
- }
- input.span5,
- textarea.span5,
- .uneditable-input.span5 {
- width: 456px;
- }
- input.span4,
- textarea.span4,
- .uneditable-input.span4 {
- width: 356px;
- }
- input.span3,
- textarea.span3,
- .uneditable-input.span3 {
- width: 256px;
- }
- input.span2,
- textarea.span2,
- .uneditable-input.span2 {
- width: 156px;
- }
- input.span1,
- textarea.span1,
- .uneditable-input.span1 {
- width: 56px;
- }
- .thumbnails {
- margin-left: -30px;
- }
- .thumbnails > li {
- margin-left: 30px;
- }
- .row-fluid .thumbnails {
- margin-left: 0;
- }
-}
-
-@media (min-width: 768px) and (max-width: 979px) {
- .row {
- margin-left: -20px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row:after {
- clear: both;
- }
- .row:before,
- .row:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 20px;
- }
- .container,
- .navbar-static-top .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 724px;
- }
- .span12 {
- width: 724px;
- }
- .span11 {
- width: 662px;
- }
- .span10 {
- width: 600px;
- }
- .span9 {
- width: 538px;
- }
- .span8 {
- width: 476px;
- }
- .span7 {
- width: 414px;
- }
- .span6 {
- width: 352px;
- }
- .span5 {
- width: 290px;
- }
- .span4 {
- width: 228px;
- }
- .span3 {
- width: 166px;
- }
- .span2 {
- width: 104px;
+ width: 1056px;
}
- .span1 {
- width: 42px;
+ input.span10,
+ textarea.span10,
+ .uneditable-input.span10 {
+ width: 956px;
}
- .offset12 {
- margin-left: 764px;
+ input.span9,
+ textarea.span9,
+ .uneditable-input.span9 {
+ width: 856px;
}
- .offset11 {
- margin-left: 702px;
+ input.span8,
+ textarea.span8,
+ .uneditable-input.span8 {
+ width: 756px;
}
- .offset10 {
- margin-left: 640px;
+ input.span7,
+ textarea.span7,
+ .uneditable-input.span7 {
+ width: 656px;
}
- .offset9 {
- margin-left: 578px;
+ input.span6,
+ textarea.span6,
+ .uneditable-input.span6 {
+ width: 556px;
}
- .offset8 {
- margin-left: 516px;
+ input.span5,
+ textarea.span5,
+ .uneditable-input.span5 {
+ width: 456px;
}
- .offset7 {
- margin-left: 454px;
+ input.span4,
+ textarea.span4,
+ .uneditable-input.span4 {
+ width: 356px;
}
- .offset6 {
- margin-left: 392px;
+ input.span3,
+ textarea.span3,
+ .uneditable-input.span3 {
+ width: 256px;
}
- .offset5 {
- margin-left: 330px;
+ input.span2,
+ textarea.span2,
+ .uneditable-input.span2 {
+ width: 156px;
}
- .offset4 {
- margin-left: 268px;
+ input.span1,
+ textarea.span1,
+ .uneditable-input.span1 {
+ width: 56px;
}
- .offset3 {
- margin-left: 206px;
+ .thumbnails {
+ margin-left: -30px;
}
- .offset2 {
- margin-left: 144px;
+ .thumbnails > li {
+ margin-left: 30px;
}
- .offset1 {
- margin-left: 82px;
+ .row-fluid .thumbnails {
+ margin-left: 0;
}
+}
+@media (min-width: 768px) and (max-width: 979px) {
.row {
margin-left: -20px;
*zoom: 1;
@@ -8073,17 +5855,8 @@ a.badge:focus {
.row:before,
.row:after {
display: table;
- line-height: 0;
content: "";
- }
- .row:after {
- clear: both;
- }
- .row:before,
- .row:after {
- display: table;
line-height: 0;
- content: "";
}
.row:after {
clear: both;
@@ -8178,432 +5951,172 @@ a.badge:focus {
.row-fluid:before,
.row-fluid:after {
display: table;
- line-height: 0;
content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
line-height: 0;
- content: "";
}
.row-fluid:after {
clear: both;
}
.row-fluid [class*="span"] {
display: block;
- float: left;
width: 100%;
min-height: 30px;
- margin-left: 2.7624309392265194%;
- *margin-left: 2.709239449864817%;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.7624309392265194%;
- }
- .row-fluid .span12 {
- width: 100%;
- *width: 99.94680851063829%;
- }
- .row-fluid .span11 {
- width: 91.43646408839778%;
- *width: 91.38327259903608%;
- }
- .row-fluid .span10 {
- width: 82.87292817679558%;
- *width: 82.81973668743387%;
- }
- .row-fluid .span9 {
- width: 74.30939226519337%;
- *width: 74.25620077583166%;
- }
- .row-fluid .span8 {
- width: 65.74585635359117%;
- *width: 65.69266486422946%;
- }
- .row-fluid .span7 {
- width: 57.18232044198895%;
- *width: 57.12912895262725%;
- }
- .row-fluid .span6 {
- width: 48.61878453038674%;
- *width: 48.56559304102504%;
- }
- .row-fluid .span5 {
- width: 40.05524861878453%;
- *width: 40.00205712942283%;
- }
- .row-fluid .span4 {
- width: 31.491712707182323%;
- *width: 31.43852121782062%;
- }
- .row-fluid .span3 {
- width: 22.92817679558011%;
- *width: 22.87498530621841%;
- }
- .row-fluid .span2 {
- width: 14.3646408839779%;
- *width: 14.311449394616199%;
- }
- .row-fluid .span1 {
- width: 5.801104972375691%;
- *width: 5.747913483013988%;
- }
- .row-fluid .offset12 {
- margin-left: 105.52486187845304%;
- *margin-left: 105.41847889972962%;
- }
- .row-fluid .offset12:first-child {
- margin-left: 102.76243093922652%;
- *margin-left: 102.6560479605031%;
- }
- .row-fluid .offset11 {
- margin-left: 96.96132596685082%;
- *margin-left: 96.8549429881274%;
- }
- .row-fluid .offset11:first-child {
- margin-left: 94.1988950276243%;
- *margin-left: 94.09251204890089%;
- }
- .row-fluid .offset10 {
- margin-left: 88.39779005524862%;
- *margin-left: 88.2914070765252%;
- }
- .row-fluid .offset10:first-child {
- margin-left: 85.6353591160221%;
- *margin-left: 85.52897613729868%;
- }
- .row-fluid .offset9 {
- margin-left: 79.8342541436464%;
- *margin-left: 79.72787116492299%;
- }
- .row-fluid .offset9:first-child {
- margin-left: 77.07182320441989%;
- *margin-left: 76.96544022569647%;
- }
- .row-fluid .offset8 {
- margin-left: 71.2707182320442%;
- *margin-left: 71.16433525332079%;
- }
- .row-fluid .offset8:first-child {
- margin-left: 68.50828729281768%;
- *margin-left: 68.40190431409427%;
- }
- .row-fluid .offset7 {
- margin-left: 62.70718232044199%;
- *margin-left: 62.600799341718584%;
- }
- .row-fluid .offset7:first-child {
- margin-left: 59.94475138121547%;
- *margin-left: 59.838368402492065%;
- }
- .row-fluid .offset6 {
- margin-left: 54.14364640883978%;
- *margin-left: 54.037263430116376%;
- }
- .row-fluid .offset6:first-child {
- margin-left: 51.38121546961326%;
- *margin-left: 51.27483249088986%;
- }
- .row-fluid .offset5 {
- margin-left: 45.58011049723757%;
- *margin-left: 45.47372751851417%;
- }
- .row-fluid .offset5:first-child {
- margin-left: 42.81767955801105%;
- *margin-left: 42.71129657928765%;
- }
- .row-fluid .offset4 {
- margin-left: 37.01657458563536%;
- *margin-left: 36.91019160691196%;
- }
- .row-fluid .offset4:first-child {
- margin-left: 34.25414364640884%;
- *margin-left: 34.14776066768544%;
- }
- .row-fluid .offset3 {
- margin-left: 28.45303867403315%;
- *margin-left: 28.346655695309746%;
- }
- .row-fluid .offset3:first-child {
- margin-left: 25.69060773480663%;
- *margin-left: 25.584224756083227%;
- }
- .row-fluid .offset2 {
- margin-left: 19.88950276243094%;
- *margin-left: 19.783119783707537%;
- }
- .row-fluid .offset2:first-child {
- margin-left: 17.12707182320442%;
- *margin-left: 17.02068884448102%;
- }
- .row-fluid .offset1 {
- margin-left: 11.32596685082873%;
- *margin-left: 11.219583872105325%;
- }
- .row-fluid .offset1:first-child {
- margin-left: 8.56353591160221%;
- *margin-left: 8.457152932878806%;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid [class*="span"] {
- display: block;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.7624309392265194%;
- *margin-left: 2.709239449864817%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ margin-left: 2.76243094%;
+ *margin-left: 2.70923945%;
}
.row-fluid [class*="span"]:first-child {
margin-left: 0;
}
.row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.7624309392265194%;
+ margin-left: 2.76243094%;
}
.row-fluid .span12 {
width: 100%;
- *width: 99.94680851063829%;
+ *width: 99.94680851%;
}
.row-fluid .span11 {
- width: 91.43646408839778%;
- *width: 91.38327259903608%;
+ width: 91.43646409%;
+ *width: 91.3832726%;
}
.row-fluid .span10 {
- width: 82.87292817679558%;
- *width: 82.81973668743387%;
+ width: 82.87292818%;
+ *width: 82.81973669%;
}
.row-fluid .span9 {
- width: 74.30939226519337%;
- *width: 74.25620077583166%;
+ width: 74.30939227%;
+ *width: 74.25620078%;
}
.row-fluid .span8 {
- width: 65.74585635359117%;
- *width: 65.69266486422946%;
+ width: 65.74585635%;
+ *width: 65.69266486%;
}
.row-fluid .span7 {
- width: 57.18232044198895%;
- *width: 57.12912895262725%;
+ width: 57.18232044%;
+ *width: 57.12912895%;
}
.row-fluid .span6 {
- width: 48.61878453038674%;
- *width: 48.56559304102504%;
+ width: 48.61878453%;
+ *width: 48.56559304%;
}
.row-fluid .span5 {
- width: 40.05524861878453%;
- *width: 40.00205712942283%;
+ width: 40.05524862%;
+ *width: 40.00205713%;
}
.row-fluid .span4 {
- width: 31.491712707182323%;
- *width: 31.43852121782062%;
+ width: 31.49171271%;
+ *width: 31.43852122%;
}
.row-fluid .span3 {
- width: 22.92817679558011%;
- *width: 22.87498530621841%;
+ width: 22.9281768%;
+ *width: 22.87498531%;
}
.row-fluid .span2 {
- width: 14.3646408839779%;
- *width: 14.311449394616199%;
+ width: 14.36464088%;
+ *width: 14.31144939%;
}
.row-fluid .span1 {
- width: 5.801104972375691%;
- *width: 5.747913483013988%;
+ width: 5.80110497%;
+ *width: 5.74791348%;
}
.row-fluid .offset12 {
- margin-left: 105.52486187845304%;
- *margin-left: 105.41847889972962%;
+ margin-left: 105.52486188%;
+ *margin-left: 105.4184789%;
}
.row-fluid .offset12:first-child {
- margin-left: 102.76243093922652%;
- *margin-left: 102.6560479605031%;
+ margin-left: 102.76243094%;
+ *margin-left: 102.65604796%;
}
.row-fluid .offset11 {
- margin-left: 96.96132596685082%;
- *margin-left: 96.8549429881274%;
+ margin-left: 96.96132597%;
+ *margin-left: 96.85494299%;
}
.row-fluid .offset11:first-child {
- margin-left: 94.1988950276243%;
- *margin-left: 94.09251204890089%;
+ margin-left: 94.19889503%;
+ *margin-left: 94.09251205%;
}
.row-fluid .offset10 {
- margin-left: 88.39779005524862%;
- *margin-left: 88.2914070765252%;
+ margin-left: 88.39779006%;
+ *margin-left: 88.29140708%;
}
.row-fluid .offset10:first-child {
- margin-left: 85.6353591160221%;
- *margin-left: 85.52897613729868%;
+ margin-left: 85.63535912%;
+ *margin-left: 85.52897614%;
}
.row-fluid .offset9 {
- margin-left: 79.8342541436464%;
- *margin-left: 79.72787116492299%;
+ margin-left: 79.83425414%;
+ *margin-left: 79.72787116%;
}
.row-fluid .offset9:first-child {
- margin-left: 77.07182320441989%;
- *margin-left: 76.96544022569647%;
+ margin-left: 77.0718232%;
+ *margin-left: 76.96544023%;
}
.row-fluid .offset8 {
- margin-left: 71.2707182320442%;
- *margin-left: 71.16433525332079%;
+ margin-left: 71.27071823%;
+ *margin-left: 71.16433525%;
}
.row-fluid .offset8:first-child {
- margin-left: 68.50828729281768%;
- *margin-left: 68.40190431409427%;
+ margin-left: 68.50828729%;
+ *margin-left: 68.40190431%;
}
.row-fluid .offset7 {
- margin-left: 62.70718232044199%;
- *margin-left: 62.600799341718584%;
+ margin-left: 62.70718232%;
+ *margin-left: 62.60079934%;
}
.row-fluid .offset7:first-child {
- margin-left: 59.94475138121547%;
- *margin-left: 59.838368402492065%;
+ margin-left: 59.94475138%;
+ *margin-left: 59.8383684%;
}
.row-fluid .offset6 {
- margin-left: 54.14364640883978%;
- *margin-left: 54.037263430116376%;
+ margin-left: 54.14364641%;
+ *margin-left: 54.03726343%;
}
.row-fluid .offset6:first-child {
- margin-left: 51.38121546961326%;
- *margin-left: 51.27483249088986%;
+ margin-left: 51.38121547%;
+ *margin-left: 51.27483249%;
}
.row-fluid .offset5 {
- margin-left: 45.58011049723757%;
- *margin-left: 45.47372751851417%;
+ margin-left: 45.5801105%;
+ *margin-left: 45.47372752%;
}
.row-fluid .offset5:first-child {
- margin-left: 42.81767955801105%;
- *margin-left: 42.71129657928765%;
+ margin-left: 42.81767956%;
+ *margin-left: 42.71129658%;
}
.row-fluid .offset4 {
- margin-left: 37.01657458563536%;
- *margin-left: 36.91019160691196%;
+ margin-left: 37.01657459%;
+ *margin-left: 36.91019161%;
}
.row-fluid .offset4:first-child {
- margin-left: 34.25414364640884%;
- *margin-left: 34.14776066768544%;
+ margin-left: 34.25414365%;
+ *margin-left: 34.14776067%;
}
.row-fluid .offset3 {
- margin-left: 28.45303867403315%;
- *margin-left: 28.346655695309746%;
+ margin-left: 28.45303867%;
+ *margin-left: 28.3466557%;
}
.row-fluid .offset3:first-child {
- margin-left: 25.69060773480663%;
- *margin-left: 25.584224756083227%;
- }
- .row-fluid .offset2 {
- margin-left: 19.88950276243094%;
- *margin-left: 19.783119783707537%;
- }
- .row-fluid .offset2:first-child {
- margin-left: 17.12707182320442%;
- *margin-left: 17.02068884448102%;
- }
- .row-fluid .offset1 {
- margin-left: 11.32596685082873%;
- *margin-left: 11.219583872105325%;
- }
- .row-fluid .offset1:first-child {
- margin-left: 8.56353591160221%;
- *margin-left: 8.457152932878806%;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- .controls-row [class*="span"] + [class*="span"] {
- margin-left: 20px;
- }
- input.span12,
- textarea.span12,
- .uneditable-input.span12 {
- width: 710px;
- }
- input.span11,
- textarea.span11,
- .uneditable-input.span11 {
- width: 648px;
- }
- input.span10,
- textarea.span10,
- .uneditable-input.span10 {
- width: 586px;
- }
- input.span9,
- textarea.span9,
- .uneditable-input.span9 {
- width: 524px;
- }
- input.span8,
- textarea.span8,
- .uneditable-input.span8 {
- width: 462px;
- }
- input.span7,
- textarea.span7,
- .uneditable-input.span7 {
- width: 400px;
- }
- input.span6,
- textarea.span6,
- .uneditable-input.span6 {
- width: 338px;
- }
- input.span5,
- textarea.span5,
- .uneditable-input.span5 {
- width: 276px;
+ margin-left: 25.69060773%;
+ *margin-left: 25.58422476%;
}
- input.span4,
- textarea.span4,
- .uneditable-input.span4 {
- width: 214px;
+ .row-fluid .offset2 {
+ margin-left: 19.88950276%;
+ *margin-left: 19.78311978%;
}
- input.span3,
- textarea.span3,
- .uneditable-input.span3 {
- width: 152px;
+ .row-fluid .offset2:first-child {
+ margin-left: 17.12707182%;
+ *margin-left: 17.02068884%;
}
- input.span2,
- textarea.span2,
- .uneditable-input.span2 {
- width: 90px;
+ .row-fluid .offset1 {
+ margin-left: 11.32596685%;
+ *margin-left: 11.21958387%;
}
- input.span1,
- textarea.span1,
- .uneditable-input.span1 {
- width: 28px;
+ .row-fluid .offset1:first-child {
+ margin-left: 8.56353591%;
+ *margin-left: 8.45715293%;
}
input,
textarea,
@@ -8674,25 +6187,24 @@ a.badge:focus {
width: 28px;
}
}
-
@media (max-width: 767px) {
body {
- padding-right: 20px;
padding-left: 20px;
+ padding-right: 20px;
}
.navbar-fixed-top,
.navbar-fixed-bottom,
.navbar-static-top {
- margin-right: -20px;
margin-left: -20px;
+ margin-right: -20px;
}
.container-fluid {
padding: 0;
}
.dl-horizontal dt {
float: none;
- width: auto;
clear: none;
+ width: auto;
text-align: left;
}
.dl-horizontal dd {
@@ -8715,20 +6227,20 @@ a.badge:focus {
[class*="span"],
.uneditable-input[class*="span"],
.row-fluid [class*="span"] {
- display: block;
float: none;
+ display: block;
width: 100%;
margin-left: 0;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.span12,
.row-fluid .span12 {
width: 100%;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.row-fluid [class*="offset"]:first-child {
margin-left: 0;
@@ -8744,8 +6256,8 @@ a.badge:focus {
width: 100%;
min-height: 30px;
-webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.input-prepend input,
.input-append input,
@@ -8760,8 +6272,8 @@ a.badge:focus {
.modal {
position: fixed;
top: 20px;
- right: 20px;
left: 20px;
+ right: 20px;
width: auto;
margin: 0;
}
@@ -8772,7 +6284,6 @@ a.badge:focus {
top: 20px;
}
}
-
@media (max-width: 480px) {
.nav-collapse {
-webkit-transform: translate3d(0, 0, 0);
@@ -8798,13 +6309,13 @@ a.badge:focus {
padding-top: 0;
}
.form-horizontal .form-actions {
- padding-right: 10px;
padding-left: 10px;
+ padding-right: 10px;
}
.media .pull-left,
.media .pull-right {
- display: block;
float: none;
+ display: block;
margin-bottom: 10px;
}
.media-object {
@@ -8813,8 +6324,8 @@ a.badge:focus {
}
.modal {
top: 10px;
- right: 10px;
left: 10px;
+ right: 10px;
}
.modal-header .close {
padding: 10px;
@@ -8824,7 +6335,6 @@ a.badge:focus {
position: static;
}
}
-
@media (max-width: 979px) {
body {
padding-top: 0;
@@ -8848,8 +6358,8 @@ a.badge:focus {
padding: 0;
}
.navbar .brand {
- padding-right: 10px;
padding-left: 10px;
+ padding-right: 10px;
margin: 0 0 0 -5px;
}
.nav-collapse {
@@ -8878,15 +6388,15 @@ a.badge:focus {
font-weight: bold;
color: #777777;
-webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
}
.nav-collapse .btn {
padding: 4px 10px 4px;
font-weight: normal;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
.nav-collapse .dropdown-menu li + li a {
margin-bottom: 2px;
@@ -8908,26 +6418,26 @@ a.badge:focus {
background-color: #111111;
}
.nav-collapse.in .btn-group {
- padding: 0;
margin-top: 5px;
+ padding: 0;
}
.nav-collapse .dropdown-menu {
position: static;
top: auto;
left: auto;
- display: none;
float: none;
+ display: none;
max-width: none;
- padding: 0;
margin: 0 15px;
+ padding: 0;
background-color: transparent;
border: none;
-webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
-webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
}
.nav-collapse .open > .dropdown-menu {
display: block;
@@ -8950,9 +6460,9 @@ a.badge:focus {
margin: 10px 0;
border-top: 1px solid #f2f2f2;
border-bottom: 1px solid #f2f2f2;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
+ -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
}
.navbar-inverse .nav-collapse .navbar-form,
.navbar-inverse .nav-collapse .navbar-search {
@@ -8965,227 +6475,39 @@ a.badge:focus {
}
.nav-collapse,
.nav-collapse.collapse {
- height: 0;
overflow: hidden;
+ height: 0;
}
.navbar .btn-navbar {
display: block;
}
.navbar-static .navbar-inner {
- padding-right: 10px;
padding-left: 10px;
+ padding-right: 10px;
}
}
-
-@media (min-width: 980px) {
+@media (min-width: 979px + 1) {
.nav-collapse.collapse {
height: auto !important;
overflow: visible !important;
}
}
-
-/**
- * Select2 Bootstrap CSS 1.0
- * Compatible with select2 3.3.2 and bootstrap 2.3.1
- * MIT License
- */
-
-.select2-container {
- vertical-align: middle;
-}
-
-.select2-container.input-mini {
- width: 60px;
-}
-
-.select2-container.input-small {
- width: 90px;
-}
-
-.select2-container.input-medium {
- width: 150px;
-}
-
-.select2-container.input-large {
- width: 210px;
-}
-
-.select2-container.input-xlarge {
- width: 270px;
-}
-
-.select2-container.input-xxlarge {
- width: 530px;
-}
-
-.select2-container.input-default {
- width: 220px;
-}
-
-.select2-container[class*="span"] {
- float: none;
- margin-left: 0;
-}
-
-.select2-container .select2-choice,
-.select2-container-multi .select2-choices {
- height: 28px;
- line-height: 29px;
- background: none;
- background-color: #ffffff;
- border: 1px solid #cccccc;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- filter: none;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.select2-container .select2-choice div,
-.select2-container.select2-container-disabled .select2-choice div,
-.select2-container .select2-choice .select2-arrow,
-.select2-container.select2-container-disabled .select2-choice .select2-arrow {
- background: none;
- border-left: none;
- filter: none;
-}
-
-.control-group.error [class^="select2-choice"] {
- border-color: #b94a48;
-}
-
-.select2-container-multi .select2-choices .select2-search-field {
- height: 28px;
- line-height: 27px;
-}
-
-.select2-container-active .select2-choice,
-.select2-container-multi.select2-container-active .select2-choices {
- border-color: rgba(82, 168, 236, 0.8);
- outline: none;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
-}
-
-[class^="input-"] .select2-container {
- font-size: 14px;
-}
-
-.input-prepend [class^="select2-choice"] {
- border-bottom-left-radius: 0;
- border-top-left-radius: 0;
-}
-
-.input-append [class^="select2-choice"] {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
-}
-
-.select2-dropdown-open [class^="select2-choice"] {
- border-bottom-right-radius: 0;
- border-bottom-left-radius: 0;
-}
-
-.select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
- border-top-right-radius: 0;
- border-top-left-radius: 0;
-}
-
-[class^="input-"] .select2-offscreen {
- position: absolute;
-}
-
-/**
- * This stops the quick flash when a native selectbox is shown and
- * then replaced by a select2 input when javascript kicks in. This can be
- * removed if javascript is not present
- */
-
-select.select2 {
- height: 28px;
- visibility: hidden;
-}
-
-body {
- position: relative;
- padding-top: 40px;
-}
-
.list-item {
- min-height: 20px;
- padding: 19px;
padding: 9px;
- margin-bottom: 20px;
- background-color: #f5f5f5;
- border: 1px solid #e3e3e3;
- -webkit-border-radius: 4px;
-webkit-border-radius: 3px;
- -moz-border-radius: 4px;
- -moz-border-radius: 3px;
- border-radius: 4px;
+ -moz-border-radius: 3px;
border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-
-.list-item blockquote {
- border-color: #ddd;
- border-color: rgba(0, 0, 0, 0.15);
-}
-
-.list-header,
-.edit-header {
- position: fixed;
- z-index: 1;
- width: 100%;
- margin-top: 11px;
- background-color: #ffffff;
-}
-
-.list-body {
- padding-top: 100px;
-}
-
-.edit-header {
- padding-top: 10px;
-}
-
-.edit-body {
- padding-top: 100px;
}
-
.page-header {
- min-height: 40px;
- padding-left: 20px;
font-family: inherit;
- font-size: 17.5px;
font-weight: bold;
color: inherit;
- border-bottom: 2px solid inherit;
-}
-
-.header-rhs {
- width: 185px;
+ font-size: 17.5px;
min-height: 40px;
- padding-right: 60px;
-}
-
-.list-header .header-rhs {
- margin: 15px 0;
}
-
.fixed-header {
- position: fixed;
- z-index: 1;
- width: 100%;
- margin-top: 11px;
background-color: #ffffff;
}
-
@media (max-width: 979px) {
.page-body {
padding-top: 0;
@@ -9193,177 +6515,45 @@ body {
.page-header {
position: static;
}
+ .global-search {
+ padding-right: 1em;
+ }
+ .global-search input {
+ width: 12em;
+ }
}
-
-.header-rhs {
- display: block;
- width: inherited !important;
- padding-right: 20px !important;
- padding-bottom: 5px;
-}
-
-.gridStyle {
- height: 400px;
- margin: auto;
- border: 1px solid #d4d4d4;
-}
-
-.gridStyle .ngTopPanel {
- background-color: #ffffff;
-}
-
-.gridStyle .ngHeaderCell {
- background-color: #e4e4e4;
-}
-
-.gridStyle .fng-right {
- text-align: right;
-}
-
-.gridStyle .fng-left {
- text-align: left;
-}
-
-.gridStyle .fng-centre,
-.gridStyle .fng-center {
- text-align: center;
-}
-
-.gridStyle .ngTotalCell {
- font-weight: bold;
-}
-
-button.form-btn {
- width: 8em;
- height: 2em;
-}
-
form.form-horizontal.compact .control-group {
margin-bottom: 2px;
}
-
-form.form-horizontal.compact input + .help-block,
-form.form-horizontal.compact select + .help-block,
-form.form-horizontal.compact textarea + .help-block,
-form.form-horizontal.compact .uneditable-input + .help-block,
-form.form-horizontal.compact .input-prepend + .help-block,
-form.form-horizontal.compact .input-append + .help-block {
- margin-top: 0;
- margin-bottom: 2px;
-}
-
-form.form-horizontal.compact hr {
- margin: 8px 0;
-}
-
form .schema-head,
form .sub-doc,
form .schema-foot {
- min-height: 20px;
- margin-bottom: 20px;
background-color: #f5f5f5;
border: 1px solid #e3e3e3;
-webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-
-form .schema-head blockquote,
-form .sub-doc blockquote,
-form .schema-foot blockquote {
- border-color: #ddd;
- border-color: rgba(0, 0, 0, 0.15);
-}
-
-form .schema-head {
- padding: 4px 180px;
- margin-top: 0;
- margin-bottom: 5px;
- border: 1px solid #ddd;
-}
-
-form .sub-doc {
- width: 97%;
- padding: 0 5px 0 0;
- margin-bottom: 3px;
-}
-
-form .sub-doc-btns {
- margin-left: 15px;
-}
-
-form .schema-foot {
- padding: 5px 180px;
- margin: 5px 0;
-}
-
-form input[type="checkbox"].ng-invalid-required:after {
- padding-left: 12px;
- font-weight: bold;
- color: red;
- content: "*";
-}
-
-form input.ng-invalid-required,
-form select.fng-invalid-required {
- background-color: rgba(255, 0, 0, 0.1);
-}
-
-form option {
- background-color: white;
-}
-
-form .fng-select2 {
- width: 220px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-
form .form-inline > .sub-doc {
- padding: 0 5px;
background-color: #ffffff;
- border: none;
- box-shadow: none;
-}
-
-.global-search {
- position: relative;
- float: right;
- width: 236px;
-}
-
-.results-container {
- position: absolute;
- top: 41px;
- right: 0;
- z-index: 3;
- width: 6000px;
-}
-
-.search-results {
- float: right;
- padding: 5px;
- background: white;
- border: 1px solid gray;
- -webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;
- -webkit-box-shadow: 10px 10px 10px #888;
- box-shadow: 10px 10px 10px #888;
}
-
.search-results .search-result {
color: #0088cc;
}
-
.search-results .search-result.focus {
- color: white;
background-color: #005580;
}
-
-@media (max-width: 979px) {
- .global-search {
- padding-right: 1em;
+.fileupload-form {
+ position: relative;
+ top: -30px;
+ margin-bottom: -30px;
+}
+.fileupload-buttonbar {
+ margin-left: 0;
+}
+@media (max-width: 767px) {
+ form .schema-head,
+ form .schema-foot {
+ padding: 5px 15px;
}
-}
\ No newline at end of file
+}
diff --git a/src/client/less/forms-angular-with-bs2.less b/src/client/less/forms-angular-with-bs2.less
new file mode 100644
index 00000000..4a9160f2
--- /dev/null
+++ b/src/client/less/forms-angular-with-bs2.less
@@ -0,0 +1,16 @@
+// Use this to generate a CSS file that includes Twitter Bootstrap v2
+@import "../../../node_modules/bootstrap-2-3-2/less/bootstrap.less";
+
+// See Marc Robichaud's answer on http://stackoverflow.com/questions/26628309/less-v2-does-not-compile-twitters-bootstrap-2-x
+#grid {
+ .core {
+ .span(@gridColumns) {
+ width: (@gridColumnWidth * @gridColumns) + (@gridGutterWidth * (@gridColumns - 1));
+ }
+ }
+};
+
+@import "forms-angular-bs-common";
+@icon-font-path: "../fonts/glyphicons/";
+@import "../../../node_modules/bootstrap-2-3-2/less/responsive";
+@import "forms-angular-bs2-specific";
diff --git a/src/client/less/forms-angular-with-bs3.css b/src/client/less/forms-angular-with-bs3.css
new file mode 100644
index 00000000..0c955805
--- /dev/null
+++ b/src/client/less/forms-angular-with-bs3.css
@@ -0,0 +1,7093 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+ font-family: sans-serif;
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+}
+body {
+ margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+audio,
+canvas,
+progress,
+video {
+ display: inline-block;
+ vertical-align: baseline;
+}
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+[hidden],
+template {
+ display: none;
+}
+a {
+ background-color: transparent;
+}
+a:active,
+a:hover {
+ outline: 0;
+}
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+b,
+strong {
+ font-weight: bold;
+}
+dfn {
+ font-style: italic;
+}
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+mark {
+ background: #ff0;
+ color: #000;
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+img {
+ border: 0;
+}
+svg:not(:root) {
+ overflow: hidden;
+}
+figure {
+ margin: 1em 40px;
+}
+hr {
+ box-sizing: content-box;
+ height: 0;
+}
+pre {
+ overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit;
+ font: inherit;
+ margin: 0;
+}
+button {
+ overflow: visible;
+}
+button,
+select {
+ text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+input {
+ line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: textfield;
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+legend {
+ border: 0;
+ padding: 0;
+}
+textarea {
+ overflow: auto;
+}
+optgroup {
+ font-weight: bold;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+td,
+th {
+ padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+ *,
+ *:before,
+ *:after {
+ background: transparent !important;
+ color: #000 !important;
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+ a[href^="#"]:after,
+ a[href^="javascript:"]:after {
+ content: "";
+ }
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ img {
+ max-width: 100% !important;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+ .navbar {
+ display: none;
+ }
+ .btn > .caret,
+ .dropup > .btn > .caret {
+ border-top-color: #000 !important;
+ }
+ .label {
+ border: 1px solid #000;
+ }
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
+ .table-bordered th,
+ .table-bordered td {
+ border: 1px solid #ddd !important;
+ }
+}
+@font-face {
+ font-family: 'Glyphicons Halflings';
+ src: url('../fonts/glyphicons-halflings-regular.eot');
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+ content: "\2a";
+}
+.glyphicon-plus:before {
+ content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+ content: "\20ac";
+}
+.glyphicon-minus:before {
+ content: "\2212";
+}
+.glyphicon-cloud:before {
+ content: "\2601";
+}
+.glyphicon-envelope:before {
+ content: "\2709";
+}
+.glyphicon-pencil:before {
+ content: "\270f";
+}
+.glyphicon-glass:before {
+ content: "\e001";
+}
+.glyphicon-music:before {
+ content: "\e002";
+}
+.glyphicon-search:before {
+ content: "\e003";
+}
+.glyphicon-heart:before {
+ content: "\e005";
+}
+.glyphicon-star:before {
+ content: "\e006";
+}
+.glyphicon-star-empty:before {
+ content: "\e007";
+}
+.glyphicon-user:before {
+ content: "\e008";
+}
+.glyphicon-film:before {
+ content: "\e009";
+}
+.glyphicon-th-large:before {
+ content: "\e010";
+}
+.glyphicon-th:before {
+ content: "\e011";
+}
+.glyphicon-th-list:before {
+ content: "\e012";
+}
+.glyphicon-ok:before {
+ content: "\e013";
+}
+.glyphicon-remove:before {
+ content: "\e014";
+}
+.glyphicon-zoom-in:before {
+ content: "\e015";
+}
+.glyphicon-zoom-out:before {
+ content: "\e016";
+}
+.glyphicon-off:before {
+ content: "\e017";
+}
+.glyphicon-signal:before {
+ content: "\e018";
+}
+.glyphicon-cog:before {
+ content: "\e019";
+}
+.glyphicon-trash:before {
+ content: "\e020";
+}
+.glyphicon-home:before {
+ content: "\e021";
+}
+.glyphicon-file:before {
+ content: "\e022";
+}
+.glyphicon-time:before {
+ content: "\e023";
+}
+.glyphicon-road:before {
+ content: "\e024";
+}
+.glyphicon-download-alt:before {
+ content: "\e025";
+}
+.glyphicon-download:before {
+ content: "\e026";
+}
+.glyphicon-upload:before {
+ content: "\e027";
+}
+.glyphicon-inbox:before {
+ content: "\e028";
+}
+.glyphicon-play-circle:before {
+ content: "\e029";
+}
+.glyphicon-repeat:before {
+ content: "\e030";
+}
+.glyphicon-refresh:before {
+ content: "\e031";
+}
+.glyphicon-list-alt:before {
+ content: "\e032";
+}
+.glyphicon-lock:before {
+ content: "\e033";
+}
+.glyphicon-flag:before {
+ content: "\e034";
+}
+.glyphicon-headphones:before {
+ content: "\e035";
+}
+.glyphicon-volume-off:before {
+ content: "\e036";
+}
+.glyphicon-volume-down:before {
+ content: "\e037";
+}
+.glyphicon-volume-up:before {
+ content: "\e038";
+}
+.glyphicon-qrcode:before {
+ content: "\e039";
+}
+.glyphicon-barcode:before {
+ content: "\e040";
+}
+.glyphicon-tag:before {
+ content: "\e041";
+}
+.glyphicon-tags:before {
+ content: "\e042";
+}
+.glyphicon-book:before {
+ content: "\e043";
+}
+.glyphicon-bookmark:before {
+ content: "\e044";
+}
+.glyphicon-print:before {
+ content: "\e045";
+}
+.glyphicon-camera:before {
+ content: "\e046";
+}
+.glyphicon-font:before {
+ content: "\e047";
+}
+.glyphicon-bold:before {
+ content: "\e048";
+}
+.glyphicon-italic:before {
+ content: "\e049";
+}
+.glyphicon-text-height:before {
+ content: "\e050";
+}
+.glyphicon-text-width:before {
+ content: "\e051";
+}
+.glyphicon-align-left:before {
+ content: "\e052";
+}
+.glyphicon-align-center:before {
+ content: "\e053";
+}
+.glyphicon-align-right:before {
+ content: "\e054";
+}
+.glyphicon-align-justify:before {
+ content: "\e055";
+}
+.glyphicon-list:before {
+ content: "\e056";
+}
+.glyphicon-indent-left:before {
+ content: "\e057";
+}
+.glyphicon-indent-right:before {
+ content: "\e058";
+}
+.glyphicon-facetime-video:before {
+ content: "\e059";
+}
+.glyphicon-picture:before {
+ content: "\e060";
+}
+.glyphicon-map-marker:before {
+ content: "\e062";
+}
+.glyphicon-adjust:before {
+ content: "\e063";
+}
+.glyphicon-tint:before {
+ content: "\e064";
+}
+.glyphicon-edit:before {
+ content: "\e065";
+}
+.glyphicon-share:before {
+ content: "\e066";
+}
+.glyphicon-check:before {
+ content: "\e067";
+}
+.glyphicon-move:before {
+ content: "\e068";
+}
+.glyphicon-step-backward:before {
+ content: "\e069";
+}
+.glyphicon-fast-backward:before {
+ content: "\e070";
+}
+.glyphicon-backward:before {
+ content: "\e071";
+}
+.glyphicon-play:before {
+ content: "\e072";
+}
+.glyphicon-pause:before {
+ content: "\e073";
+}
+.glyphicon-stop:before {
+ content: "\e074";
+}
+.glyphicon-forward:before {
+ content: "\e075";
+}
+.glyphicon-fast-forward:before {
+ content: "\e076";
+}
+.glyphicon-step-forward:before {
+ content: "\e077";
+}
+.glyphicon-eject:before {
+ content: "\e078";
+}
+.glyphicon-chevron-left:before {
+ content: "\e079";
+}
+.glyphicon-chevron-right:before {
+ content: "\e080";
+}
+.glyphicon-plus-sign:before {
+ content: "\e081";
+}
+.glyphicon-minus-sign:before {
+ content: "\e082";
+}
+.glyphicon-remove-sign:before {
+ content: "\e083";
+}
+.glyphicon-ok-sign:before {
+ content: "\e084";
+}
+.glyphicon-question-sign:before {
+ content: "\e085";
+}
+.glyphicon-info-sign:before {
+ content: "\e086";
+}
+.glyphicon-screenshot:before {
+ content: "\e087";
+}
+.glyphicon-remove-circle:before {
+ content: "\e088";
+}
+.glyphicon-ok-circle:before {
+ content: "\e089";
+}
+.glyphicon-ban-circle:before {
+ content: "\e090";
+}
+.glyphicon-arrow-left:before {
+ content: "\e091";
+}
+.glyphicon-arrow-right:before {
+ content: "\e092";
+}
+.glyphicon-arrow-up:before {
+ content: "\e093";
+}
+.glyphicon-arrow-down:before {
+ content: "\e094";
+}
+.glyphicon-share-alt:before {
+ content: "\e095";
+}
+.glyphicon-resize-full:before {
+ content: "\e096";
+}
+.glyphicon-resize-small:before {
+ content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+ content: "\e101";
+}
+.glyphicon-gift:before {
+ content: "\e102";
+}
+.glyphicon-leaf:before {
+ content: "\e103";
+}
+.glyphicon-fire:before {
+ content: "\e104";
+}
+.glyphicon-eye-open:before {
+ content: "\e105";
+}
+.glyphicon-eye-close:before {
+ content: "\e106";
+}
+.glyphicon-warning-sign:before {
+ content: "\e107";
+}
+.glyphicon-plane:before {
+ content: "\e108";
+}
+.glyphicon-calendar:before {
+ content: "\e109";
+}
+.glyphicon-random:before {
+ content: "\e110";
+}
+.glyphicon-comment:before {
+ content: "\e111";
+}
+.glyphicon-magnet:before {
+ content: "\e112";
+}
+.glyphicon-chevron-up:before {
+ content: "\e113";
+}
+.glyphicon-chevron-down:before {
+ content: "\e114";
+}
+.glyphicon-retweet:before {
+ content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+ content: "\e116";
+}
+.glyphicon-folder-close:before {
+ content: "\e117";
+}
+.glyphicon-folder-open:before {
+ content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+ content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+ content: "\e120";
+}
+.glyphicon-hdd:before {
+ content: "\e121";
+}
+.glyphicon-bullhorn:before {
+ content: "\e122";
+}
+.glyphicon-bell:before {
+ content: "\e123";
+}
+.glyphicon-certificate:before {
+ content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+ content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+ content: "\e126";
+}
+.glyphicon-hand-right:before {
+ content: "\e127";
+}
+.glyphicon-hand-left:before {
+ content: "\e128";
+}
+.glyphicon-hand-up:before {
+ content: "\e129";
+}
+.glyphicon-hand-down:before {
+ content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+ content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+ content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+ content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+ content: "\e134";
+}
+.glyphicon-globe:before {
+ content: "\e135";
+}
+.glyphicon-wrench:before {
+ content: "\e136";
+}
+.glyphicon-tasks:before {
+ content: "\e137";
+}
+.glyphicon-filter:before {
+ content: "\e138";
+}
+.glyphicon-briefcase:before {
+ content: "\e139";
+}
+.glyphicon-fullscreen:before {
+ content: "\e140";
+}
+.glyphicon-dashboard:before {
+ content: "\e141";
+}
+.glyphicon-paperclip:before {
+ content: "\e142";
+}
+.glyphicon-heart-empty:before {
+ content: "\e143";
+}
+.glyphicon-link:before {
+ content: "\e144";
+}
+.glyphicon-phone:before {
+ content: "\e145";
+}
+.glyphicon-pushpin:before {
+ content: "\e146";
+}
+.glyphicon-usd:before {
+ content: "\e148";
+}
+.glyphicon-gbp:before {
+ content: "\e149";
+}
+.glyphicon-sort:before {
+ content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+ content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+ content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+ content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+ content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+ content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+ content: "\e156";
+}
+.glyphicon-unchecked:before {
+ content: "\e157";
+}
+.glyphicon-expand:before {
+ content: "\e158";
+}
+.glyphicon-collapse-down:before {
+ content: "\e159";
+}
+.glyphicon-collapse-up:before {
+ content: "\e160";
+}
+.glyphicon-log-in:before {
+ content: "\e161";
+}
+.glyphicon-flash:before {
+ content: "\e162";
+}
+.glyphicon-log-out:before {
+ content: "\e163";
+}
+.glyphicon-new-window:before {
+ content: "\e164";
+}
+.glyphicon-record:before {
+ content: "\e165";
+}
+.glyphicon-save:before {
+ content: "\e166";
+}
+.glyphicon-open:before {
+ content: "\e167";
+}
+.glyphicon-saved:before {
+ content: "\e168";
+}
+.glyphicon-import:before {
+ content: "\e169";
+}
+.glyphicon-export:before {
+ content: "\e170";
+}
+.glyphicon-send:before {
+ content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+ content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+ content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+ content: "\e174";
+}
+.glyphicon-floppy-save:before {
+ content: "\e175";
+}
+.glyphicon-floppy-open:before {
+ content: "\e176";
+}
+.glyphicon-credit-card:before {
+ content: "\e177";
+}
+.glyphicon-transfer:before {
+ content: "\e178";
+}
+.glyphicon-cutlery:before {
+ content: "\e179";
+}
+.glyphicon-header:before {
+ content: "\e180";
+}
+.glyphicon-compressed:before {
+ content: "\e181";
+}
+.glyphicon-earphone:before {
+ content: "\e182";
+}
+.glyphicon-phone-alt:before {
+ content: "\e183";
+}
+.glyphicon-tower:before {
+ content: "\e184";
+}
+.glyphicon-stats:before {
+ content: "\e185";
+}
+.glyphicon-sd-video:before {
+ content: "\e186";
+}
+.glyphicon-hd-video:before {
+ content: "\e187";
+}
+.glyphicon-subtitles:before {
+ content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+ content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+ content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+ content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+ content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+ content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+ content: "\e194";
+}
+.glyphicon-registration-mark:before {
+ content: "\e195";
+}
+.glyphicon-cloud-download:before {
+ content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+ content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+ content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+ content: "\e200";
+}
+.glyphicon-cd:before {
+ content: "\e201";
+}
+.glyphicon-save-file:before {
+ content: "\e202";
+}
+.glyphicon-open-file:before {
+ content: "\e203";
+}
+.glyphicon-level-up:before {
+ content: "\e204";
+}
+.glyphicon-copy:before {
+ content: "\e205";
+}
+.glyphicon-paste:before {
+ content: "\e206";
+}
+.glyphicon-alert:before {
+ content: "\e209";
+}
+.glyphicon-equalizer:before {
+ content: "\e210";
+}
+.glyphicon-king:before {
+ content: "\e211";
+}
+.glyphicon-queen:before {
+ content: "\e212";
+}
+.glyphicon-pawn:before {
+ content: "\e213";
+}
+.glyphicon-bishop:before {
+ content: "\e214";
+}
+.glyphicon-knight:before {
+ content: "\e215";
+}
+.glyphicon-baby-formula:before {
+ content: "\e216";
+}
+.glyphicon-tent:before {
+ content: "\26fa";
+}
+.glyphicon-blackboard:before {
+ content: "\e218";
+}
+.glyphicon-bed:before {
+ content: "\e219";
+}
+.glyphicon-apple:before {
+ content: "\f8ff";
+}
+.glyphicon-erase:before {
+ content: "\e221";
+}
+.glyphicon-hourglass:before {
+ content: "\231b";
+}
+.glyphicon-lamp:before {
+ content: "\e223";
+}
+.glyphicon-duplicate:before {
+ content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+ content: "\e225";
+}
+.glyphicon-scissors:before {
+ content: "\e226";
+}
+.glyphicon-bitcoin:before {
+ content: "\e227";
+}
+.glyphicon-btc:before {
+ content: "\e227";
+}
+.glyphicon-xbt:before {
+ content: "\e227";
+}
+.glyphicon-yen:before {
+ content: "\00a5";
+}
+.glyphicon-jpy:before {
+ content: "\00a5";
+}
+.glyphicon-ruble:before {
+ content: "\20bd";
+}
+.glyphicon-rub:before {
+ content: "\20bd";
+}
+.glyphicon-scale:before {
+ content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+ content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+ content: "\e232";
+}
+.glyphicon-education:before {
+ content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+ content: "\e234";
+}
+.glyphicon-option-vertical:before {
+ content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+ content: "\e236";
+}
+.glyphicon-modal-window:before {
+ content: "\e237";
+}
+.glyphicon-oil:before {
+ content: "\e238";
+}
+.glyphicon-grain:before {
+ content: "\e239";
+}
+.glyphicon-sunglasses:before {
+ content: "\e240";
+}
+.glyphicon-text-size:before {
+ content: "\e241";
+}
+.glyphicon-text-color:before {
+ content: "\e242";
+}
+.glyphicon-text-background:before {
+ content: "\e243";
+}
+.glyphicon-object-align-top:before {
+ content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+ content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+ content: "\e246";
+}
+.glyphicon-object-align-left:before {
+ content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+ content: "\e248";
+}
+.glyphicon-object-align-right:before {
+ content: "\e249";
+}
+.glyphicon-triangle-right:before {
+ content: "\e250";
+}
+.glyphicon-triangle-left:before {
+ content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+ content: "\e252";
+}
+.glyphicon-triangle-top:before {
+ content: "\e253";
+}
+.glyphicon-console:before {
+ content: "\e254";
+}
+.glyphicon-superscript:before {
+ content: "\e255";
+}
+.glyphicon-subscript:before {
+ content: "\e256";
+}
+.glyphicon-menu-left:before {
+ content: "\e257";
+}
+.glyphicon-menu-right:before {
+ content: "\e258";
+}
+.glyphicon-menu-down:before {
+ content: "\e259";
+}
+.glyphicon-menu-up:before {
+ content: "\e260";
+}
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+html {
+ font-size: 10px;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #333333;
+ background-color: #ffffff;
+}
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+a {
+ color: #337ab7;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #23527c;
+ text-decoration: underline;
+}
+a:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+figure {
+ margin: 0;
+}
+img {
+ vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+.img-rounded {
+ border-radius: 6px;
+}
+.img-thumbnail {
+ padding: 4px;
+ line-height: 1.42857143;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ border-radius: 4px;
+ -webkit-transition: all 0.2s ease-in-out;
+ -o-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+ display: inline-block;
+ max-width: 100%;
+ height: auto;
+}
+.img-circle {
+ border-radius: 50%;
+}
+hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #eeeeee;
+}
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+}
+[role="button"] {
+ cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: inherit;
+ font-weight: 500;
+ line-height: 1.1;
+ color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+ font-weight: normal;
+ line-height: 1;
+ color: #777777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+ font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+ font-size: 75%;
+}
+h1,
+.h1 {
+ font-size: 36px;
+}
+h2,
+.h2 {
+ font-size: 30px;
+}
+h3,
+.h3 {
+ font-size: 24px;
+}
+h4,
+.h4 {
+ font-size: 18px;
+}
+h5,
+.h5 {
+ font-size: 14px;
+}
+h6,
+.h6 {
+ font-size: 12px;
+}
+p {
+ margin: 0 0 10px;
+}
+.lead {
+ margin-bottom: 20px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.4;
+}
+@media (min-width: 768px) {
+ .lead {
+ font-size: 21px;
+ }
+}
+small,
+.small {
+ font-size: 85%;
+}
+mark,
+.mark {
+ background-color: #fcf8e3;
+ padding: .2em;
+}
+.text-left {
+ text-align: left;
+}
+.text-right {
+ text-align: right;
+}
+.text-center {
+ text-align: center;
+}
+.text-justify {
+ text-align: justify;
+}
+.text-nowrap {
+ white-space: nowrap;
+}
+.text-lowercase {
+ text-transform: lowercase;
+}
+.text-uppercase {
+ text-transform: uppercase;
+}
+.text-capitalize {
+ text-transform: capitalize;
+}
+.text-muted {
+ color: #777777;
+}
+.text-primary {
+ color: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+ color: #286090;
+}
+.text-success {
+ color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+ color: #2b542c;
+}
+.text-info {
+ color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+ color: #245269;
+}
+.text-warning {
+ color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #66512c;
+}
+.text-danger {
+ color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+ color: #843534;
+}
+.bg-primary {
+ color: #fff;
+ background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+ background-color: #286090;
+}
+.bg-success {
+ background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+ background-color: #c1e2b3;
+}
+.bg-info {
+ background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+ background-color: #afd9ee;
+}
+.bg-warning {
+ background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+ background-color: #f7ecb5;
+}
+.bg-danger {
+ background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+ background-color: #e4b9b9;
+}
+.page-header {
+ padding-bottom: 9px;
+ margin: 40px 0 20px;
+ border-bottom: 1px solid #eeeeee;
+}
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+.list-inline {
+ padding-left: 0;
+ list-style: none;
+ margin-left: -5px;
+}
+.list-inline > li {
+ display: inline-block;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+dl {
+ margin-top: 0;
+ margin-bottom: 20px;
+}
+dt,
+dd {
+ line-height: 1.42857143;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .dl-horizontal dt {
+ float: left;
+ width: 160px;
+ clear: left;
+ text-align: right;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dl-horizontal dd {
+ margin-left: 180px;
+ }
+}
+abbr[title],
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted #777777;
+}
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+blockquote {
+ padding: 10px 20px;
+ margin: 0 0 20px;
+ font-size: 17.5px;
+ border-left: 5px solid #eeeeee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+ margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+ display: block;
+ font-size: 80%;
+ line-height: 1.42857143;
+ color: #777777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+ content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+ padding-right: 15px;
+ padding-left: 0;
+ border-right: 5px solid #eeeeee;
+ border-left: 0;
+ text-align: right;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+ content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+ content: '\00A0 \2014';
+}
+address {
+ margin-bottom: 20px;
+ font-style: normal;
+ line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #c7254e;
+ background-color: #f9f2f4;
+ border-radius: 4px;
+}
+kbd {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #ffffff;
+ background-color: #333333;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+kbd kbd {
+ padding: 0;
+ font-size: 100%;
+ font-weight: bold;
+ box-shadow: none;
+}
+pre {
+ display: block;
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ line-height: 1.42857143;
+ word-break: break-all;
+ word-wrap: break-word;
+ color: #333333;
+ background-color: #f5f5f5;
+ border: 1px solid #cccccc;
+ border-radius: 4px;
+}
+pre code {
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border-radius: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+.container {
+ margin-right: auto;
+ margin-left: auto;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+@media (min-width: 768px) {
+ .container {
+ width: 750px;
+ }
+}
+@media (min-width: 992px) {
+ .container {
+ width: 970px;
+ }
+}
+@media (min-width: 1200px) {
+ .container {
+ width: 1170px;
+ }
+}
+.container-fluid {
+ margin-right: auto;
+ margin-left: auto;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+.row {
+ margin-left: -15px;
+ margin-right: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+ position: relative;
+ min-height: 1px;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+ float: left;
+}
+.col-xs-12 {
+ width: 100%;
+}
+.col-xs-11 {
+ width: 91.66666667%;
+}
+.col-xs-10 {
+ width: 83.33333333%;
+}
+.col-xs-9 {
+ width: 75%;
+}
+.col-xs-8 {
+ width: 66.66666667%;
+}
+.col-xs-7 {
+ width: 58.33333333%;
+}
+.col-xs-6 {
+ width: 50%;
+}
+.col-xs-5 {
+ width: 41.66666667%;
+}
+.col-xs-4 {
+ width: 33.33333333%;
+}
+.col-xs-3 {
+ width: 25%;
+}
+.col-xs-2 {
+ width: 16.66666667%;
+}
+.col-xs-1 {
+ width: 8.33333333%;
+}
+.col-xs-pull-12 {
+ right: 100%;
+}
+.col-xs-pull-11 {
+ right: 91.66666667%;
+}
+.col-xs-pull-10 {
+ right: 83.33333333%;
+}
+.col-xs-pull-9 {
+ right: 75%;
+}
+.col-xs-pull-8 {
+ right: 66.66666667%;
+}
+.col-xs-pull-7 {
+ right: 58.33333333%;
+}
+.col-xs-pull-6 {
+ right: 50%;
+}
+.col-xs-pull-5 {
+ right: 41.66666667%;
+}
+.col-xs-pull-4 {
+ right: 33.33333333%;
+}
+.col-xs-pull-3 {
+ right: 25%;
+}
+.col-xs-pull-2 {
+ right: 16.66666667%;
+}
+.col-xs-pull-1 {
+ right: 8.33333333%;
+}
+.col-xs-pull-0 {
+ right: auto;
+}
+.col-xs-push-12 {
+ left: 100%;
+}
+.col-xs-push-11 {
+ left: 91.66666667%;
+}
+.col-xs-push-10 {
+ left: 83.33333333%;
+}
+.col-xs-push-9 {
+ left: 75%;
+}
+.col-xs-push-8 {
+ left: 66.66666667%;
+}
+.col-xs-push-7 {
+ left: 58.33333333%;
+}
+.col-xs-push-6 {
+ left: 50%;
+}
+.col-xs-push-5 {
+ left: 41.66666667%;
+}
+.col-xs-push-4 {
+ left: 33.33333333%;
+}
+.col-xs-push-3 {
+ left: 25%;
+}
+.col-xs-push-2 {
+ left: 16.66666667%;
+}
+.col-xs-push-1 {
+ left: 8.33333333%;
+}
+.col-xs-push-0 {
+ left: auto;
+}
+.col-xs-offset-12 {
+ margin-left: 100%;
+}
+.col-xs-offset-11 {
+ margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+ margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+ margin-left: 75%;
+}
+.col-xs-offset-8 {
+ margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+ margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+ margin-left: 50%;
+}
+.col-xs-offset-5 {
+ margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+ margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+ margin-left: 25%;
+}
+.col-xs-offset-2 {
+ margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+ margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+ margin-left: 0%;
+}
+@media (min-width: 768px) {
+ .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+ float: left;
+ }
+ .col-sm-12 {
+ width: 100%;
+ }
+ .col-sm-11 {
+ width: 91.66666667%;
+ }
+ .col-sm-10 {
+ width: 83.33333333%;
+ }
+ .col-sm-9 {
+ width: 75%;
+ }
+ .col-sm-8 {
+ width: 66.66666667%;
+ }
+ .col-sm-7 {
+ width: 58.33333333%;
+ }
+ .col-sm-6 {
+ width: 50%;
+ }
+ .col-sm-5 {
+ width: 41.66666667%;
+ }
+ .col-sm-4 {
+ width: 33.33333333%;
+ }
+ .col-sm-3 {
+ width: 25%;
+ }
+ .col-sm-2 {
+ width: 16.66666667%;
+ }
+ .col-sm-1 {
+ width: 8.33333333%;
+ }
+ .col-sm-pull-12 {
+ right: 100%;
+ }
+ .col-sm-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-sm-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-sm-pull-9 {
+ right: 75%;
+ }
+ .col-sm-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-sm-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-sm-pull-6 {
+ right: 50%;
+ }
+ .col-sm-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-sm-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-sm-pull-3 {
+ right: 25%;
+ }
+ .col-sm-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-sm-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-sm-pull-0 {
+ right: auto;
+ }
+ .col-sm-push-12 {
+ left: 100%;
+ }
+ .col-sm-push-11 {
+ left: 91.66666667%;
+ }
+ .col-sm-push-10 {
+ left: 83.33333333%;
+ }
+ .col-sm-push-9 {
+ left: 75%;
+ }
+ .col-sm-push-8 {
+ left: 66.66666667%;
+ }
+ .col-sm-push-7 {
+ left: 58.33333333%;
+ }
+ .col-sm-push-6 {
+ left: 50%;
+ }
+ .col-sm-push-5 {
+ left: 41.66666667%;
+ }
+ .col-sm-push-4 {
+ left: 33.33333333%;
+ }
+ .col-sm-push-3 {
+ left: 25%;
+ }
+ .col-sm-push-2 {
+ left: 16.66666667%;
+ }
+ .col-sm-push-1 {
+ left: 8.33333333%;
+ }
+ .col-sm-push-0 {
+ left: auto;
+ }
+ .col-sm-offset-12 {
+ margin-left: 100%;
+ }
+ .col-sm-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-sm-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-sm-offset-9 {
+ margin-left: 75%;
+ }
+ .col-sm-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-sm-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-sm-offset-6 {
+ margin-left: 50%;
+ }
+ .col-sm-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-sm-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-sm-offset-3 {
+ margin-left: 25%;
+ }
+ .col-sm-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-sm-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-sm-offset-0 {
+ margin-left: 0%;
+ }
+}
+@media (min-width: 992px) {
+ .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+ float: left;
+ }
+ .col-md-12 {
+ width: 100%;
+ }
+ .col-md-11 {
+ width: 91.66666667%;
+ }
+ .col-md-10 {
+ width: 83.33333333%;
+ }
+ .col-md-9 {
+ width: 75%;
+ }
+ .col-md-8 {
+ width: 66.66666667%;
+ }
+ .col-md-7 {
+ width: 58.33333333%;
+ }
+ .col-md-6 {
+ width: 50%;
+ }
+ .col-md-5 {
+ width: 41.66666667%;
+ }
+ .col-md-4 {
+ width: 33.33333333%;
+ }
+ .col-md-3 {
+ width: 25%;
+ }
+ .col-md-2 {
+ width: 16.66666667%;
+ }
+ .col-md-1 {
+ width: 8.33333333%;
+ }
+ .col-md-pull-12 {
+ right: 100%;
+ }
+ .col-md-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-md-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-md-pull-9 {
+ right: 75%;
+ }
+ .col-md-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-md-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-md-pull-6 {
+ right: 50%;
+ }
+ .col-md-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-md-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-md-pull-3 {
+ right: 25%;
+ }
+ .col-md-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-md-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-md-pull-0 {
+ right: auto;
+ }
+ .col-md-push-12 {
+ left: 100%;
+ }
+ .col-md-push-11 {
+ left: 91.66666667%;
+ }
+ .col-md-push-10 {
+ left: 83.33333333%;
+ }
+ .col-md-push-9 {
+ left: 75%;
+ }
+ .col-md-push-8 {
+ left: 66.66666667%;
+ }
+ .col-md-push-7 {
+ left: 58.33333333%;
+ }
+ .col-md-push-6 {
+ left: 50%;
+ }
+ .col-md-push-5 {
+ left: 41.66666667%;
+ }
+ .col-md-push-4 {
+ left: 33.33333333%;
+ }
+ .col-md-push-3 {
+ left: 25%;
+ }
+ .col-md-push-2 {
+ left: 16.66666667%;
+ }
+ .col-md-push-1 {
+ left: 8.33333333%;
+ }
+ .col-md-push-0 {
+ left: auto;
+ }
+ .col-md-offset-12 {
+ margin-left: 100%;
+ }
+ .col-md-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-md-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-md-offset-9 {
+ margin-left: 75%;
+ }
+ .col-md-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-md-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-md-offset-6 {
+ margin-left: 50%;
+ }
+ .col-md-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-md-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-md-offset-3 {
+ margin-left: 25%;
+ }
+ .col-md-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-md-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-md-offset-0 {
+ margin-left: 0%;
+ }
+}
+@media (min-width: 1200px) {
+ .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+ float: left;
+ }
+ .col-lg-12 {
+ width: 100%;
+ }
+ .col-lg-11 {
+ width: 91.66666667%;
+ }
+ .col-lg-10 {
+ width: 83.33333333%;
+ }
+ .col-lg-9 {
+ width: 75%;
+ }
+ .col-lg-8 {
+ width: 66.66666667%;
+ }
+ .col-lg-7 {
+ width: 58.33333333%;
+ }
+ .col-lg-6 {
+ width: 50%;
+ }
+ .col-lg-5 {
+ width: 41.66666667%;
+ }
+ .col-lg-4 {
+ width: 33.33333333%;
+ }
+ .col-lg-3 {
+ width: 25%;
+ }
+ .col-lg-2 {
+ width: 16.66666667%;
+ }
+ .col-lg-1 {
+ width: 8.33333333%;
+ }
+ .col-lg-pull-12 {
+ right: 100%;
+ }
+ .col-lg-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-lg-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-lg-pull-9 {
+ right: 75%;
+ }
+ .col-lg-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-lg-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-lg-pull-6 {
+ right: 50%;
+ }
+ .col-lg-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-lg-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-lg-pull-3 {
+ right: 25%;
+ }
+ .col-lg-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-lg-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-lg-pull-0 {
+ right: auto;
+ }
+ .col-lg-push-12 {
+ left: 100%;
+ }
+ .col-lg-push-11 {
+ left: 91.66666667%;
+ }
+ .col-lg-push-10 {
+ left: 83.33333333%;
+ }
+ .col-lg-push-9 {
+ left: 75%;
+ }
+ .col-lg-push-8 {
+ left: 66.66666667%;
+ }
+ .col-lg-push-7 {
+ left: 58.33333333%;
+ }
+ .col-lg-push-6 {
+ left: 50%;
+ }
+ .col-lg-push-5 {
+ left: 41.66666667%;
+ }
+ .col-lg-push-4 {
+ left: 33.33333333%;
+ }
+ .col-lg-push-3 {
+ left: 25%;
+ }
+ .col-lg-push-2 {
+ left: 16.66666667%;
+ }
+ .col-lg-push-1 {
+ left: 8.33333333%;
+ }
+ .col-lg-push-0 {
+ left: auto;
+ }
+ .col-lg-offset-12 {
+ margin-left: 100%;
+ }
+ .col-lg-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-lg-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-lg-offset-9 {
+ margin-left: 75%;
+ }
+ .col-lg-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-lg-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-lg-offset-6 {
+ margin-left: 50%;
+ }
+ .col-lg-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-lg-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-lg-offset-3 {
+ margin-left: 25%;
+ }
+ .col-lg-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-lg-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-lg-offset-0 {
+ margin-left: 0%;
+ }
+}
+table {
+ background-color: transparent;
+}
+caption {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ color: #777777;
+ text-align: left;
+}
+th {
+ text-align: left;
+}
+.table {
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+ padding: 8px;
+ line-height: 1.42857143;
+ vertical-align: top;
+ border-top: 1px solid #dddddd;
+}
+.table > thead > tr > th {
+ vertical-align: bottom;
+ border-bottom: 2px solid #dddddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+ border-top: 0;
+}
+.table > tbody + tbody {
+ border-top: 2px solid #dddddd;
+}
+.table .table {
+ background-color: #ffffff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+ padding: 5px;
+}
+.table-bordered {
+ border: 1px solid #dddddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+ border: 1px solid #dddddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+ border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+ background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+ background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+ position: static;
+ float: none;
+ display: table-column;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+ position: static;
+ float: none;
+ display: table-cell;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+ background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+ background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+ background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+ background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+ background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+ background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+ background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+ background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+ background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+ background-color: #ebcccc;
+}
+.table-responsive {
+ overflow-x: auto;
+ min-height: 0.01%;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ width: 100%;
+ margin-bottom: 15px;
+ overflow-y: hidden;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ border: 1px solid #dddddd;
+ }
+ .table-responsive > .table {
+ margin-bottom: 0;
+ }
+ .table-responsive > .table > thead > tr > th,
+ .table-responsive > .table > tbody > tr > th,
+ .table-responsive > .table > tfoot > tr > th,
+ .table-responsive > .table > thead > tr > td,
+ .table-responsive > .table > tbody > tr > td,
+ .table-responsive > .table > tfoot > tr > td {
+ white-space: nowrap;
+ }
+ .table-responsive > .table-bordered {
+ border: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:first-child,
+ .table-responsive > .table-bordered > tbody > tr > th:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+ .table-responsive > .table-bordered > thead > tr > td:first-child,
+ .table-responsive > .table-bordered > tbody > tr > td:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:last-child,
+ .table-responsive > .table-bordered > tbody > tr > th:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+ .table-responsive > .table-bordered > thead > tr > td:last-child,
+ .table-responsive > .table-bordered > tbody > tr > td:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+ }
+ .table-responsive > .table-bordered > tbody > tr:last-child > th,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+ .table-responsive > .table-bordered > tbody > tr:last-child > td,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+ border-bottom: 0;
+ }
+}
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ min-width: 0;
+}
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 20px;
+ font-size: 21px;
+ line-height: inherit;
+ color: #333333;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+}
+label {
+ display: inline-block;
+ max-width: 100%;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+input[type="search"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9;
+ line-height: normal;
+}
+input[type="file"] {
+ display: block;
+}
+input[type="range"] {
+ display: block;
+ width: 100%;
+}
+select[multiple],
+select[size] {
+ height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+output {
+ display: block;
+ padding-top: 7px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555555;
+}
+.form-control {
+ display: block;
+ width: 100%;
+ height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555555;
+ background-color: #ffffff;
+ background-image: none;
+ border: 1px solid #cccccc;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+ border-color: #66afe9;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.form-control::-moz-placeholder {
+ color: #999999;
+ opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+ color: #999999;
+}
+.form-control::-webkit-input-placeholder {
+ color: #999999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+ background-color: #eeeeee;
+ opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+ cursor: not-allowed;
+}
+textarea.form-control {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"].form-control,
+ input[type="time"].form-control,
+ input[type="datetime-local"].form-control,
+ input[type="month"].form-control {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm,
+ .input-group-sm input[type="date"],
+ .input-group-sm input[type="time"],
+ .input-group-sm input[type="datetime-local"],
+ .input-group-sm input[type="month"] {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg,
+ .input-group-lg input[type="date"],
+ .input-group-lg input[type="time"],
+ .input-group-lg input[type="datetime-local"],
+ .input-group-lg input[type="month"] {
+ line-height: 46px;
+ }
+}
+.form-group {
+ margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+ position: relative;
+ display: block;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+ min-height: 20px;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+ position: absolute;
+ margin-left: -20px;
+ margin-top: 4px \9;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+ margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+ position: relative;
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ vertical-align: middle;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+ cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+ cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+ cursor: not-allowed;
+}
+.form-control-static {
+ padding-top: 7px;
+ padding-bottom: 7px;
+ margin-bottom: 0;
+ min-height: 34px;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+ padding-left: 0;
+ padding-right: 0;
+}
+.input-sm {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-sm {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+ height: auto;
+}
+.form-group-sm .form-control {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.form-group-sm select.form-control {
+ height: 30px;
+ line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+ height: auto;
+}
+.form-group-sm .form-control-static {
+ height: 30px;
+ min-height: 32px;
+ padding: 6px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.input-lg {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-lg {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+ height: auto;
+}
+.form-group-lg .form-control {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.form-group-lg select.form-control {
+ height: 46px;
+ line-height: 46px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+ height: auto;
+}
+.form-group-lg .form-control-static {
+ height: 46px;
+ min-height: 38px;
+ padding: 11px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.has-feedback {
+ position: relative;
+}
+.has-feedback .form-control {
+ padding-right: 42.5px;
+}
+.form-control-feedback {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 2;
+ display: block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+ width: 46px;
+ height: 46px;
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+ color: #3c763d;
+}
+.has-success .form-control {
+ border-color: #3c763d;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-success .form-control:focus {
+ border-color: #2b542c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+ color: #3c763d;
+ border-color: #3c763d;
+ background-color: #dff0d8;
+}
+.has-success .form-control-feedback {
+ color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+ color: #8a6d3b;
+}
+.has-warning .form-control {
+ border-color: #8a6d3b;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-warning .form-control:focus {
+ border-color: #66512c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+ color: #8a6d3b;
+ border-color: #8a6d3b;
+ background-color: #fcf8e3;
+}
+.has-warning .form-control-feedback {
+ color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+ color: #a94442;
+}
+.has-error .form-control {
+ border-color: #a94442;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-error .form-control:focus {
+ border-color: #843534;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+ color: #a94442;
+ border-color: #a94442;
+ background-color: #f2dede;
+}
+.has-error .form-control-feedback {
+ color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+ top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+ top: 0;
+}
+.help-block {
+ display: block;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ color: #737373;
+}
+@media (min-width: 768px) {
+ .form-inline .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-control-static {
+ display: inline-block;
+ }
+ .form-inline .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .form-inline .input-group .input-group-addon,
+ .form-inline .input-group .input-group-btn,
+ .form-inline .input-group .form-control {
+ width: auto;
+ }
+ .form-inline .input-group > .form-control {
+ width: 100%;
+ }
+ .form-inline .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio,
+ .form-inline .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio label,
+ .form-inline .checkbox label {
+ padding-left: 0;
+ }
+ .form-inline .radio input[type="radio"],
+ .form-inline .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .form-inline .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-top: 7px;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+ min-height: 27px;
+}
+.form-horizontal .form-group {
+ margin-left: -15px;
+ margin-right: -15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .control-label {
+ text-align: right;
+ margin-bottom: 0;
+ padding-top: 7px;
+ }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+ right: 15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-lg .control-label {
+ padding-top: 14.333333px;
+ font-size: 18px;
+ }
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-sm .control-label {
+ padding-top: 6px;
+ font-size: 12px;
+ }
+}
+.btn {
+ display: inline-block;
+ margin-bottom: 0;
+ font-weight: normal;
+ text-align: center;
+ vertical-align: middle;
+ touch-action: manipulation;
+ cursor: pointer;
+ background-image: none;
+ border: 1px solid transparent;
+ white-space: nowrap;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ border-radius: 4px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+ color: #333333;
+ text-decoration: none;
+}
+.btn:active,
+.btn.active {
+ outline: 0;
+ background-image: none;
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+ cursor: not-allowed;
+ opacity: 0.65;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+ pointer-events: none;
+}
+.btn-default {
+ color: #333333;
+ background-color: #ffffff;
+ border-color: #cccccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+ color: #333333;
+ background-color: #e6e6e6;
+ border-color: #8c8c8c;
+}
+.btn-default:hover {
+ color: #333333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ color: #333333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+ color: #333333;
+ background-color: #d4d4d4;
+ border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #ffffff;
+ border-color: #cccccc;
+}
+.btn-default .badge {
+ color: #ffffff;
+ background-color: #333333;
+}
+.btn-primary {
+ color: #ffffff;
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+ color: #ffffff;
+ background-color: #286090;
+ border-color: #122b40;
+}
+.btn-primary:hover {
+ color: #ffffff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ color: #ffffff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+ color: #ffffff;
+ background-color: #204d74;
+ border-color: #122b40;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary .badge {
+ color: #337ab7;
+ background-color: #ffffff;
+}
+.btn-success {
+ color: #ffffff;
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+ color: #ffffff;
+ background-color: #449d44;
+ border-color: #255625;
+}
+.btn-success:hover {
+ color: #ffffff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ color: #ffffff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+ color: #ffffff;
+ background-color: #398439;
+ border-color: #255625;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success .badge {
+ color: #5cb85c;
+ background-color: #ffffff;
+}
+.btn-info {
+ color: #ffffff;
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info:focus,
+.btn-info.focus {
+ color: #ffffff;
+ background-color: #31b0d5;
+ border-color: #1b6d85;
+}
+.btn-info:hover {
+ color: #ffffff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ color: #ffffff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+ color: #ffffff;
+ background-color: #269abc;
+ border-color: #1b6d85;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info .badge {
+ color: #5bc0de;
+ background-color: #ffffff;
+}
+.btn-warning {
+ color: #ffffff;
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+ color: #ffffff;
+ background-color: #ec971f;
+ border-color: #985f0d;
+}
+.btn-warning:hover {
+ color: #ffffff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ color: #ffffff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+ color: #ffffff;
+ background-color: #d58512;
+ border-color: #985f0d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning .badge {
+ color: #f0ad4e;
+ background-color: #ffffff;
+}
+.btn-danger {
+ color: #ffffff;
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+ color: #ffffff;
+ background-color: #c9302c;
+ border-color: #761c19;
+}
+.btn-danger:hover {
+ color: #ffffff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ color: #ffffff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+ color: #ffffff;
+ background-color: #ac2925;
+ border-color: #761c19;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger .badge {
+ color: #d9534f;
+ background-color: #ffffff;
+}
+.btn-link {
+ color: #337ab7;
+ font-weight: normal;
+ border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+ background-color: transparent;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+ border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+ color: #23527c;
+ text-decoration: underline;
+ background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+ color: #777777;
+ text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+ padding: 1px 5px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-block {
+ display: block;
+ width: 100%;
+}
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity 0.15s linear;
+ -o-transition: opacity 0.15s linear;
+ transition: opacity 0.15s linear;
+}
+.fade.in {
+ opacity: 1;
+}
+.collapse {
+ display: none;
+}
+.collapse.in {
+ display: block;
+}
+tr.collapse.in {
+ display: table-row;
+}
+tbody.collapse.in {
+ display: table-row-group;
+}
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ -webkit-transition-property: height, visibility;
+ transition-property: height, visibility;
+ -webkit-transition-duration: 0.35s;
+ transition-duration: 0.35s;
+ -webkit-transition-timing-function: ease;
+ transition-timing-function: ease;
+}
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: 4px dashed;
+ border-top: 4px solid \9;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle:focus {
+ outline: 0;
+}
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ list-style: none;
+ font-size: 14px;
+ text-align: left;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ background-clip: padding-box;
+}
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu .divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.42857143;
+ color: #333333;
+ white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ text-decoration: none;
+ color: #262626;
+ background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #ffffff;
+ text-decoration: none;
+ outline: 0;
+ background-color: #337ab7;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #777777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ background-color: transparent;
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ cursor: not-allowed;
+}
+.open > .dropdown-menu {
+ display: block;
+}
+.open > a {
+ outline: 0;
+}
+.dropdown-menu-right {
+ left: auto;
+ right: 0;
+}
+.dropdown-menu-left {
+ left: 0;
+ right: auto;
+}
+.dropdown-header {
+ display: block;
+ padding: 3px 20px;
+ font-size: 12px;
+ line-height: 1.42857143;
+ color: #777777;
+ white-space: nowrap;
+}
+.dropdown-backdrop {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ z-index: 990;
+}
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ border-top: 0;
+ border-bottom: 4px dashed;
+ border-bottom: 4px solid \9;
+ content: "";
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 2px;
+}
+@media (min-width: 768px) {
+ .navbar-right .dropdown-menu {
+ left: auto;
+ right: 0;
+ }
+ .navbar-right .dropdown-menu-left {
+ left: 0;
+ right: auto;
+ }
+}
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+ z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+ margin-left: -1px;
+}
+.btn-toolbar {
+ margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+ float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+ margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+ border-radius: 0;
+}
+.btn-group > .btn:first-child {
+ margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+.btn-group > .btn-group {
+ float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+ padding-left: 8px;
+ padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+ padding-left: 12px;
+ padding-right: 12px;
+}
+.btn-group.open .dropdown-toggle {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn .caret {
+ margin-left: 0;
+}
+.btn-lg .caret {
+ border-width: 5px 5px 0;
+ border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+ border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+ display: block;
+ float: none;
+ width: 100%;
+ max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+ float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+ margin-top: -1px;
+ margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+ border-bottom-left-radius: 4px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+.btn-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+ float: none;
+ display: table-cell;
+ width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+ width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+ left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+.input-group {
+ position: relative;
+ display: table;
+ border-collapse: separate;
+}
+.input-group[class*="col-"] {
+ float: none;
+ padding-left: 0;
+ padding-right: 0;
+}
+.input-group .form-control {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 100%;
+ margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+ display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+.input-group-addon {
+ padding: 6px 12px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1;
+ color: #555555;
+ text-align: center;
+ background-color: #eeeeee;
+ border: 1px solid #cccccc;
+ border-radius: 4px;
+}
+.input-group-addon.input-sm {
+ padding: 5px 10px;
+ font-size: 12px;
+ border-radius: 3px;
+}
+.input-group-addon.input-lg {
+ padding: 10px 16px;
+ font-size: 18px;
+ border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+ margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+.input-group-addon:first-child {
+ border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+.input-group-addon:last-child {
+ border-left: 0;
+}
+.input-group-btn {
+ position: relative;
+ font-size: 0;
+ white-space: nowrap;
+}
+.input-group-btn > .btn {
+ position: relative;
+}
+.input-group-btn > .btn + .btn {
+ margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+ z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+ margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+ z-index: 2;
+ margin-left: -1px;
+}
+.nav {
+ margin-bottom: 0;
+ padding-left: 0;
+ list-style: none;
+}
+.nav > li {
+ position: relative;
+ display: block;
+}
+.nav > li > a {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: #eeeeee;
+}
+.nav > li.disabled > a {
+ color: #777777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+ color: #777777;
+ text-decoration: none;
+ background-color: transparent;
+ cursor: not-allowed;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+ background-color: #eeeeee;
+ border-color: #337ab7;
+}
+.nav .nav-divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.nav > li > a > img {
+ max-width: none;
+}
+.nav-tabs {
+ border-bottom: 1px solid #dddddd;
+}
+.nav-tabs > li {
+ float: left;
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ margin-right: 2px;
+ line-height: 1.42857143;
+ border: 1px solid transparent;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eeeeee #eeeeee #dddddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+ color: #555555;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+.nav-tabs.nav-justified {
+ width: 100%;
+ border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+ float: none;
+}
+.nav-tabs.nav-justified > li > a {
+ text-align: center;
+ margin-bottom: 5px;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-tabs.nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs.nav-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+ border: 1px solid #dddddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li > a {
+ border-bottom: 1px solid #dddddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs.nav-justified > .active > a,
+ .nav-tabs.nav-justified > .active > a:hover,
+ .nav-tabs.nav-justified > .active > a:focus {
+ border-bottom-color: #ffffff;
+ }
+}
+.nav-pills > li {
+ float: left;
+}
+.nav-pills > li > a {
+ border-radius: 4px;
+}
+.nav-pills > li + li {
+ margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ color: #ffffff;
+ background-color: #337ab7;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li + li {
+ margin-top: 2px;
+ margin-left: 0;
+}
+.nav-justified {
+ width: 100%;
+}
+.nav-justified > li {
+ float: none;
+}
+.nav-justified > li > a {
+ text-align: center;
+ margin-bottom: 5px;
+}
+.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs-justified {
+ border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+ border: 1px solid #dddddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs-justified > li > a {
+ border-bottom: 1px solid #dddddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs-justified > .active > a,
+ .nav-tabs-justified > .active > a:hover,
+ .nav-tabs-justified > .active > a:focus {
+ border-bottom-color: #ffffff;
+ }
+}
+.tab-content > .tab-pane {
+ display: none;
+}
+.tab-content > .active {
+ display: block;
+}
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+.navbar {
+ position: relative;
+ min-height: 50px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+ .navbar {
+ border-radius: 4px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-header {
+ float: left;
+ }
+}
+.navbar-collapse {
+ overflow-x: visible;
+ padding-right: 15px;
+ padding-left: 15px;
+ border-top: 1px solid transparent;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ -webkit-overflow-scrolling: touch;
+}
+.navbar-collapse.in {
+ overflow-y: auto;
+}
+@media (min-width: 768px) {
+ .navbar-collapse {
+ width: auto;
+ border-top: 0;
+ box-shadow: none;
+ }
+ .navbar-collapse.collapse {
+ display: block !important;
+ height: auto !important;
+ padding-bottom: 0;
+ overflow: visible !important;
+ }
+ .navbar-collapse.in {
+ overflow-y: visible;
+ }
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-static-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+ max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ max-height: 200px;
+ }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .container > .navbar-header,
+ .container-fluid > .navbar-header,
+ .container > .navbar-collapse,
+ .container-fluid > .navbar-collapse {
+ margin-right: 0;
+ margin-left: 0;
+ }
+}
+.navbar-static-top {
+ z-index: 1000;
+ border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+ .navbar-static-top {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+@media (min-width: 768px) {
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top {
+ top: 0;
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+ margin-bottom: 0;
+ border-width: 1px 0 0;
+}
+.navbar-brand {
+ float: left;
+ padding: 15px 15px;
+ font-size: 18px;
+ line-height: 20px;
+ height: 50px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+ text-decoration: none;
+}
+.navbar-brand > img {
+ display: block;
+}
+@media (min-width: 768px) {
+ .navbar > .container .navbar-brand,
+ .navbar > .container-fluid .navbar-brand {
+ margin-left: -15px;
+ }
+}
+.navbar-toggle {
+ position: relative;
+ float: right;
+ margin-right: 15px;
+ padding: 9px 10px;
+ margin-top: 8px;
+ margin-bottom: 8px;
+ background-color: transparent;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.navbar-toggle:focus {
+ outline: 0;
+}
+.navbar-toggle .icon-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+ margin-top: 4px;
+}
+@media (min-width: 768px) {
+ .navbar-toggle {
+ display: none;
+ }
+}
+.navbar-nav {
+ margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: 20px;
+}
+@media (max-width: 767px) {
+ .navbar-nav .open .dropdown-menu {
+ position: static;
+ float: none;
+ width: auto;
+ margin-top: 0;
+ background-color: transparent;
+ border: 0;
+ box-shadow: none;
+ }
+ .navbar-nav .open .dropdown-menu > li > a,
+ .navbar-nav .open .dropdown-menu .dropdown-header {
+ padding: 5px 15px 5px 25px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a {
+ line-height: 20px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-nav .open .dropdown-menu > li > a:focus {
+ background-image: none;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-nav {
+ float: left;
+ margin: 0;
+ }
+ .navbar-nav > li {
+ float: left;
+ }
+ .navbar-nav > li > a {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ }
+}
+.navbar-form {
+ margin-left: -15px;
+ margin-right: -15px;
+ padding: 10px 15px;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+@media (min-width: 768px) {
+ .navbar-form .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control-static {
+ display: inline-block;
+ }
+ .navbar-form .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .navbar-form .input-group .input-group-addon,
+ .navbar-form .input-group .input-group-btn,
+ .navbar-form .input-group .form-control {
+ width: auto;
+ }
+ .navbar-form .input-group > .form-control {
+ width: 100%;
+ }
+ .navbar-form .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio,
+ .navbar-form .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio label,
+ .navbar-form .checkbox label {
+ padding-left: 0;
+ }
+ .navbar-form .radio input[type="radio"],
+ .navbar-form .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .navbar-form .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+.navbar-form .row {
+ margin-left: 5px;
+ margin-right: 0;
+}
+.navbar-form .form-group .input-group {
+ display: table-cell;
+}
+.navbar-form .form-group .input-group .input-group-addon {
+ display: none;
+}
+@media (max-width: 767px) {
+ .navbar-form .form-group {
+ margin-bottom: 5px;
+ }
+ .navbar-form .form-group:last-child {
+ margin-bottom: 0;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-form {
+ width: auto;
+ border: 0;
+ margin-left: 0;
+ margin-right: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+}
+.navbar-nav > li > .dropdown-menu {
+ margin-top: 0;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ margin-bottom: 0;
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.navbar-btn {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+ margin-top: 14px;
+ margin-bottom: 14px;
+}
+.navbar-text {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+@media (min-width: 768px) {
+ .navbar-text {
+ float: left;
+ margin-left: 15px;
+ margin-right: 15px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-left {
+ float: left !important;
+ }
+ .navbar-right {
+ float: right !important;
+ margin-right: -15px;
+ }
+ .navbar-right ~ .navbar-right {
+ margin-right: 0;
+ }
+}
+.navbar-default {
+ background-color: #f8f8f8;
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+ color: #777777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+ color: #5e5e5e;
+ background-color: transparent;
+}
+.navbar-default .navbar-text {
+ color: #777777;
+}
+.navbar-default .navbar-nav > li > a {
+ color: #777777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+ color: #333333;
+ background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+ color: #555555;
+ background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+ color: #cccccc;
+ background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+ border-color: #dddddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+ background-color: #dddddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+ background-color: #888888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+ background-color: #e7e7e7;
+ color: #555555;
+}
+@media (max-width: 767px) {
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+ color: #777777;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #333333;
+ background-color: transparent;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #555555;
+ background-color: #e7e7e7;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #cccccc;
+ background-color: transparent;
+ }
+}
+.navbar-default .navbar-link {
+ color: #777777;
+}
+.navbar-default .navbar-link:hover {
+ color: #333333;
+}
+.navbar-default .btn-link {
+ color: #777777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+ color: #333333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+ color: #cccccc;
+}
+.navbar-inverse {
+ background-color: #222222;
+ border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+ color: #ffffff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+ color: #ffffff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+ color: #ffffff;
+ background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+ color: #444444;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+ border-color: #333333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+ background-color: #333333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+ background-color: #ffffff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+ border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+ background-color: #080808;
+ color: #ffffff;
+}
+@media (max-width: 767px) {
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+ border-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+ color: #9d9d9d;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #ffffff;
+ background-color: transparent;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #ffffff;
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #444444;
+ background-color: transparent;
+ }
+}
+.navbar-inverse .navbar-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+ color: #ffffff;
+}
+.navbar-inverse .btn-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+ color: #ffffff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+ color: #444444;
+}
+.breadcrumb {
+ padding: 8px 15px;
+ margin-bottom: 20px;
+ list-style: none;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+.breadcrumb > li {
+ display: inline-block;
+}
+.breadcrumb > li + li:before {
+ content: "/\00a0";
+ padding: 0 5px;
+ color: #cccccc;
+}
+.breadcrumb > .active {
+ color: #777777;
+}
+.pagination {
+ display: inline-block;
+ padding-left: 0;
+ margin: 20px 0;
+ border-radius: 4px;
+}
+.pagination > li {
+ display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+ position: relative;
+ float: left;
+ padding: 6px 12px;
+ line-height: 1.42857143;
+ text-decoration: none;
+ color: #337ab7;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ margin-left: -1px;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+ margin-left: 0;
+ border-bottom-left-radius: 4px;
+ border-top-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+ border-bottom-right-radius: 4px;
+ border-top-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+ z-index: 3;
+ color: #23527c;
+ background-color: #eeeeee;
+ border-color: #dddddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+ z-index: 2;
+ color: #ffffff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+ cursor: default;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+ color: #777777;
+ background-color: #ffffff;
+ border-color: #dddddd;
+ cursor: not-allowed;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+ border-bottom-left-radius: 6px;
+ border-top-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+ border-bottom-right-radius: 6px;
+ border-top-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+ border-bottom-left-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+ border-bottom-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.pager {
+ padding-left: 0;
+ margin: 20px 0;
+ list-style: none;
+ text-align: center;
+}
+.pager li {
+ display: inline;
+}
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #eeeeee;
+}
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: #777777;
+ background-color: #ffffff;
+ cursor: not-allowed;
+}
+.label {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: #ffffff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+ color: #ffffff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.label:empty {
+ display: none;
+}
+.btn .label {
+ position: relative;
+ top: -1px;
+}
+.label-default {
+ background-color: #777777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+ background-color: #5e5e5e;
+}
+.label-primary {
+ background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+ background-color: #286090;
+}
+.label-success {
+ background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+ background-color: #449d44;
+}
+.label-info {
+ background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+ background-color: #31b0d5;
+}
+.label-warning {
+ background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+ background-color: #ec971f;
+}
+.label-danger {
+ background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+ background-color: #c9302c;
+}
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ font-weight: bold;
+ color: #ffffff;
+ line-height: 1;
+ vertical-align: middle;
+ white-space: nowrap;
+ text-align: center;
+ background-color: #777777;
+ border-radius: 10px;
+}
+.badge:empty {
+ display: none;
+}
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+ top: 0;
+ padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+ color: #ffffff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: #337ab7;
+ background-color: #ffffff;
+}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
+.jumbotron {
+ padding-top: 30px;
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+ color: inherit;
+ background-color: #eeeeee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+ color: inherit;
+}
+.jumbotron p {
+ margin-bottom: 15px;
+ font-size: 21px;
+ font-weight: 200;
+}
+.jumbotron > hr {
+ border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+ border-radius: 6px;
+}
+.jumbotron .container {
+ max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+ .jumbotron {
+ padding-top: 48px;
+ padding-bottom: 48px;
+ }
+ .container .jumbotron,
+ .container-fluid .jumbotron {
+ padding-left: 60px;
+ padding-right: 60px;
+ }
+ .jumbotron h1,
+ .jumbotron .h1 {
+ font-size: 63px;
+ }
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ margin-bottom: 20px;
+ line-height: 1.42857143;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ border-radius: 4px;
+ -webkit-transition: border 0.2s ease-in-out;
+ -o-transition: border 0.2s ease-in-out;
+ transition: border 0.2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+ margin-left: auto;
+ margin-right: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+ border-color: #337ab7;
+}
+.thumbnail .caption {
+ padding: 9px;
+ color: #333333;
+}
+.alert {
+ padding: 15px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.alert h4 {
+ margin-top: 0;
+ color: inherit;
+}
+.alert .alert-link {
+ font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+ margin-bottom: 0;
+}
+.alert > p + p {
+ margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+ padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+}
+.alert-success {
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+ color: #3c763d;
+}
+.alert-success hr {
+ border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+ color: #2b542c;
+}
+.alert-info {
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+ color: #31708f;
+}
+.alert-info hr {
+ border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+ color: #245269;
+}
+.alert-warning {
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+ color: #8a6d3b;
+}
+.alert-warning hr {
+ border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+ color: #66512c;
+}
+.alert-danger {
+ background-color: #f2dede;
+ border-color: #ebccd1;
+ color: #a94442;
+}
+.alert-danger hr {
+ border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+ color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+.progress {
+ overflow: hidden;
+ height: 20px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+.progress-bar {
+ float: left;
+ width: 0%;
+ height: 100%;
+ font-size: 12px;
+ line-height: 20px;
+ color: #ffffff;
+ text-align: center;
+ background-color: #337ab7;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -webkit-transition: width 0.6s ease;
+ -o-transition: width 0.6s ease;
+ transition: width 0.6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+ background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+ background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+ background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+ background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+.media,
+.media-body {
+ zoom: 1;
+ overflow: hidden;
+}
+.media-body {
+ width: 10000px;
+}
+.media-object {
+ display: block;
+}
+.media-object.img-thumbnail {
+ max-width: none;
+}
+.media-right,
+.media > .pull-right {
+ padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+ padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+ display: table-cell;
+ vertical-align: top;
+}
+.media-middle {
+ vertical-align: middle;
+}
+.media-bottom {
+ vertical-align: bottom;
+}
+.media-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.media-list {
+ padding-left: 0;
+ list-style: none;
+}
+.list-group {
+ margin-bottom: 20px;
+ padding-left: 0;
+}
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ margin-bottom: -1px;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+}
+.list-group-item:first-child {
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+}
+.list-group-item:last-child {
+ margin-bottom: 0;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+a.list-group-item,
+button.list-group-item {
+ color: #555555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+ color: #333333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+ text-decoration: none;
+ color: #555555;
+ background-color: #f5f5f5;
+}
+button.list-group-item {
+ width: 100%;
+ text-align: left;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+ background-color: #eeeeee;
+ color: #777777;
+ cursor: not-allowed;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+ color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+ color: #777777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ z-index: 2;
+ color: #ffffff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+ color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+ color: #c7ddef;
+}
+.list-group-item-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+ color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+ color: #3c763d;
+ background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.list-group-item-success.active:focus {
+ color: #fff;
+ background-color: #3c763d;
+ border-color: #3c763d;
+}
+.list-group-item-info {
+ color: #31708f;
+ background-color: #d9edf7;
+}
+a.list-group-item-info,
+button.list-group-item-info {
+ color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+ color: #31708f;
+ background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.list-group-item-info.active:focus {
+ color: #fff;
+ background-color: #31708f;
+ border-color: #31708f;
+}
+.list-group-item-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+}
+a.list-group-item-warning,
+button.list-group-item-warning {
+ color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+ color: #8a6d3b;
+ background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.list-group-item-warning.active:focus {
+ color: #fff;
+ background-color: #8a6d3b;
+ border-color: #8a6d3b;
+}
+.list-group-item-danger {
+ color: #a94442;
+ background-color: #f2dede;
+}
+a.list-group-item-danger,
+button.list-group-item-danger {
+ color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+ color: #a94442;
+ background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.list-group-item-danger.active:focus {
+ color: #fff;
+ background-color: #a94442;
+ border-color: #a94442;
+}
+.list-group-item-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.list-group-item-text {
+ margin-bottom: 0;
+ line-height: 1.3;
+}
+.panel {
+ margin-bottom: 20px;
+ background-color: #ffffff;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.panel-body {
+ padding: 15px;
+}
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+ color: inherit;
+}
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 16px;
+ color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+ color: inherit;
+}
+.panel-footer {
+ padding: 10px 15px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #dddddd;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+ margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+ border-width: 1px 0;
+ border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+ border-top: 0;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+ border-bottom: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+ border-top-width: 0;
+}
+.list-group + .panel-footer {
+ border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+ margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+ padding-left: 15px;
+ padding-right: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+ border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+ border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+ border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+ border-top: 1px solid #dddddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+ border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+ border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+ border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+ border-bottom: 0;
+}
+.panel > .table-responsive {
+ border: 0;
+ margin-bottom: 0;
+}
+.panel-group {
+ margin-bottom: 20px;
+}
+.panel-group .panel {
+ margin-bottom: 0;
+ border-radius: 4px;
+}
+.panel-group .panel + .panel {
+ margin-top: 5px;
+}
+.panel-group .panel-heading {
+ border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: 1px solid #dddddd;
+}
+.panel-group .panel-footer {
+ border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+ border-bottom: 1px solid #dddddd;
+}
+.panel-default {
+ border-color: #dddddd;
+}
+.panel-default > .panel-heading {
+ color: #333333;
+ background-color: #f5f5f5;
+ border-color: #dddddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #dddddd;
+}
+.panel-default > .panel-heading .badge {
+ color: #f5f5f5;
+ background-color: #333333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #dddddd;
+}
+.panel-primary {
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+ color: #ffffff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+ color: #337ab7;
+ background-color: #ffffff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #337ab7;
+}
+.panel-success {
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+ color: #dff0d8;
+ background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #d6e9c6;
+}
+.panel-info {
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+ color: #d9edf7;
+ background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #bce8f1;
+}
+.panel-warning {
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+ color: #fcf8e3;
+ background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #faebcc;
+}
+.panel-danger {
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+ color: #f2dede;
+ background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+ position: relative;
+ display: block;
+ height: 0;
+ padding: 0;
+ overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ height: 100%;
+ width: 100%;
+ border: 0;
+}
+.embed-responsive-16by9 {
+ padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+ padding-bottom: 75%;
+}
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.well-lg {
+ padding: 24px;
+ border-radius: 6px;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: 3px;
+}
+.close {
+ float: right;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1;
+ color: #000000;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+.close:hover,
+.close:focus {
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+button.close {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+}
+.modal-open {
+ overflow: hidden;
+}
+.modal {
+ display: none;
+ overflow: hidden;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1050;
+ -webkit-overflow-scrolling: touch;
+ outline: 0;
+}
+.modal.fade .modal-dialog {
+ -webkit-transform: translate(0, -25%);
+ -ms-transform: translate(0, -25%);
+ -o-transform: translate(0, -25%);
+ transform: translate(0, -25%);
+ -webkit-transition: -webkit-transform 0.3s ease-out;
+ -moz-transition: -moz-transform 0.3s ease-out;
+ -o-transition: -o-transform 0.3s ease-out;
+ transition: transform 0.3s ease-out;
+}
+.modal.in .modal-dialog {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.modal-open .modal {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 10px;
+}
+.modal-content {
+ position: relative;
+ background-color: #ffffff;
+ border: 1px solid #999999;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ background-clip: padding-box;
+ outline: 0;
+}
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000000;
+}
+.modal-backdrop.fade {
+ opacity: 0;
+ filter: alpha(opacity=0);
+}
+.modal-backdrop.in {
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+.modal-header {
+ padding: 15px;
+ border-bottom: 1px solid #e5e5e5;
+ min-height: 16.42857143px;
+}
+.modal-header .close {
+ margin-top: -2px;
+}
+.modal-title {
+ margin: 0;
+ line-height: 1.42857143;
+}
+.modal-body {
+ position: relative;
+ padding: 15px;
+}
+.modal-footer {
+ padding: 15px;
+ text-align: right;
+ border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+ margin-left: 5px;
+ margin-bottom: 0;
+}
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+.modal-scrollbar-measure {
+ position: absolute;
+ top: -9999px;
+ width: 50px;
+ height: 50px;
+ overflow: scroll;
+}
+@media (min-width: 768px) {
+ .modal-dialog {
+ width: 600px;
+ margin: 30px auto;
+ }
+ .modal-content {
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+ }
+ .modal-sm {
+ width: 300px;
+ }
+}
+@media (min-width: 992px) {
+ .modal-lg {
+ width: 900px;
+ }
+}
+.tooltip {
+ position: absolute;
+ z-index: 1070;
+ display: block;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ letter-spacing: normal;
+ line-break: auto;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ white-space: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ font-size: 12px;
+ opacity: 0;
+ filter: alpha(opacity=0);
+}
+.tooltip.in {
+ opacity: 0.9;
+ filter: alpha(opacity=90);
+}
+.tooltip.top {
+ margin-top: -3px;
+ padding: 5px 0;
+}
+.tooltip.right {
+ margin-left: 3px;
+ padding: 0 5px;
+}
+.tooltip.bottom {
+ margin-top: 3px;
+ padding: 5px 0;
+}
+.tooltip.left {
+ margin-left: -3px;
+ padding: 0 5px;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #ffffff;
+ text-align: center;
+ background-color: #000000;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000000;
+}
+.tooltip.top-left .tooltip-arrow {
+ bottom: 0;
+ right: 5px;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000000;
+}
+.tooltip.top-right .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-width: 5px 5px 5px 0;
+ border-right-color: #000000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-width: 5px 0 5px 5px;
+ border-left-color: #000000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+ top: 0;
+ right: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000000;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ letter-spacing: normal;
+ line-break: auto;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ white-space: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ font-size: 14px;
+ background-color: #ffffff;
+ background-clip: padding-box;
+ border: 1px solid #cccccc;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+}
+.popover.top {
+ margin-top: -10px;
+}
+.popover.right {
+ margin-left: 10px;
+}
+.popover.bottom {
+ margin-top: 10px;
+}
+.popover.left {
+ margin-left: -10px;
+}
+.popover-title {
+ margin: 0;
+ padding: 8px 14px;
+ font-size: 14px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-radius: 5px 5px 0 0;
+}
+.popover-content {
+ padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover > .arrow {
+ border-width: 11px;
+}
+.popover > .arrow:after {
+ border-width: 10px;
+ content: "";
+}
+.popover.top > .arrow {
+ left: 50%;
+ margin-left: -11px;
+ border-bottom-width: 0;
+ border-top-color: #999999;
+ border-top-color: rgba(0, 0, 0, 0.25);
+ bottom: -11px;
+}
+.popover.top > .arrow:after {
+ content: " ";
+ bottom: 1px;
+ margin-left: -10px;
+ border-bottom-width: 0;
+ border-top-color: #ffffff;
+}
+.popover.right > .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-left-width: 0;
+ border-right-color: #999999;
+ border-right-color: rgba(0, 0, 0, 0.25);
+}
+.popover.right > .arrow:after {
+ content: " ";
+ left: 1px;
+ bottom: -10px;
+ border-left-width: 0;
+ border-right-color: #ffffff;
+}
+.popover.bottom > .arrow {
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #999999;
+ border-bottom-color: rgba(0, 0, 0, 0.25);
+ top: -11px;
+}
+.popover.bottom > .arrow:after {
+ content: " ";
+ top: 1px;
+ margin-left: -10px;
+ border-top-width: 0;
+ border-bottom-color: #ffffff;
+}
+.popover.left > .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-right-width: 0;
+ border-left-color: #999999;
+ border-left-color: rgba(0, 0, 0, 0.25);
+}
+.popover.left > .arrow:after {
+ content: " ";
+ right: 1px;
+ border-right-width: 0;
+ border-left-color: #ffffff;
+ bottom: -10px;
+}
+.carousel {
+ position: relative;
+}
+.carousel-inner {
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+}
+.carousel-inner > .item {
+ display: none;
+ position: relative;
+ -webkit-transition: 0.6s ease-in-out left;
+ -o-transition: 0.6s ease-in-out left;
+ transition: 0.6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+ .carousel-inner > .item {
+ -webkit-transition: -webkit-transform 0.6s ease-in-out;
+ -moz-transition: -moz-transform 0.6s ease-in-out;
+ -o-transition: -o-transform 0.6s ease-in-out;
+ transition: transform 0.6s ease-in-out;
+ -webkit-backface-visibility: hidden;
+ -moz-backface-visibility: hidden;
+ backface-visibility: hidden;
+ -webkit-perspective: 1000px;
+ -moz-perspective: 1000px;
+ perspective: 1000px;
+ }
+ .carousel-inner > .item.next,
+ .carousel-inner > .item.active.right {
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ left: 0;
+ }
+ .carousel-inner > .item.prev,
+ .carousel-inner > .item.active.left {
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ left: 0;
+ }
+ .carousel-inner > .item.next.left,
+ .carousel-inner > .item.prev.right,
+ .carousel-inner > .item.active {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ left: 0;
+ }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ display: block;
+}
+.carousel-inner > .active {
+ left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.carousel-inner > .next {
+ left: 100%;
+}
+.carousel-inner > .prev {
+ left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+ left: 0;
+}
+.carousel-inner > .active.left {
+ left: -100%;
+}
+.carousel-inner > .active.right {
+ left: 100%;
+}
+.carousel-control {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 15%;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+ font-size: 20px;
+ color: #ffffff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-control.left {
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+}
+.carousel-control.right {
+ left: auto;
+ right: 0;
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+}
+.carousel-control:hover,
+.carousel-control:focus {
+ outline: 0;
+ color: #ffffff;
+ text-decoration: none;
+ opacity: 0.9;
+ filter: alpha(opacity=90);
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+ position: absolute;
+ top: 50%;
+ margin-top: -10px;
+ z-index: 5;
+ display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+ left: 50%;
+ margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+ right: 50%;
+ margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+ width: 20px;
+ height: 20px;
+ line-height: 1;
+ font-family: serif;
+}
+.carousel-control .icon-prev:before {
+ content: '\2039';
+}
+.carousel-control .icon-next:before {
+ content: '\203a';
+}
+.carousel-indicators {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ z-index: 15;
+ width: 60%;
+ margin-left: -30%;
+ padding-left: 0;
+ list-style: none;
+ text-align: center;
+}
+.carousel-indicators li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ text-indent: -999px;
+ border: 1px solid #ffffff;
+ border-radius: 10px;
+ cursor: pointer;
+ background-color: #000 \9;
+ background-color: rgba(0, 0, 0, 0);
+}
+.carousel-indicators .active {
+ margin: 0;
+ width: 12px;
+ height: 12px;
+ background-color: #ffffff;
+}
+.carousel-caption {
+ position: absolute;
+ left: 15%;
+ right: 15%;
+ bottom: 20px;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: #ffffff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-caption .btn {
+ text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-prev,
+ .carousel-control .icon-next {
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ font-size: 30px;
+ }
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .icon-prev {
+ margin-left: -15px;
+ }
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-next {
+ margin-right: -15px;
+ }
+ .carousel-caption {
+ left: 20%;
+ right: 20%;
+ padding-bottom: 30px;
+ }
+ .carousel-indicators {
+ bottom: 20px;
+ }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+ content: " ";
+ display: table;
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+ clear: both;
+}
+.center-block {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+.pull-right {
+ float: right !important;
+}
+.pull-left {
+ float: left !important;
+}
+.hide {
+ display: none !important;
+}
+.show {
+ display: block !important;
+}
+.invisible {
+ visibility: hidden;
+}
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.hidden {
+ display: none !important;
+}
+.affix {
+ position: fixed;
+}
+@-ms-viewport {
+ width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+ display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+ display: none !important;
+}
+@media (max-width: 767px) {
+ .visible-xs {
+ display: block !important;
+ }
+ table.visible-xs {
+ display: table !important;
+ }
+ tr.visible-xs {
+ display: table-row !important;
+ }
+ th.visible-xs,
+ td.visible-xs {
+ display: table-cell !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-block {
+ display: block !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline {
+ display: inline !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm {
+ display: block !important;
+ }
+ table.visible-sm {
+ display: table !important;
+ }
+ tr.visible-sm {
+ display: table-row !important;
+ }
+ th.visible-sm,
+ td.visible-sm {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-block {
+ display: block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md {
+ display: block !important;
+ }
+ table.visible-md {
+ display: table !important;
+ }
+ tr.visible-md {
+ display: table-row !important;
+ }
+ th.visible-md,
+ td.visible-md {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-block {
+ display: block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg {
+ display: block !important;
+ }
+ table.visible-lg {
+ display: table !important;
+ }
+ tr.visible-lg {
+ display: table-row !important;
+ }
+ th.visible-lg,
+ td.visible-lg {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-block {
+ display: block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (max-width: 767px) {
+ .hidden-xs {
+ display: none !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .hidden-sm {
+ display: none !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .hidden-md {
+ display: none !important;
+ }
+}
+@media (min-width: 1200px) {
+ .hidden-lg {
+ display: none !important;
+ }
+}
+.visible-print {
+ display: none !important;
+}
+@media print {
+ .visible-print {
+ display: block !important;
+ }
+ table.visible-print {
+ display: table !important;
+ }
+ tr.visible-print {
+ display: table-row !important;
+ }
+ th.visible-print,
+ td.visible-print {
+ display: table-cell !important;
+ }
+}
+.visible-print-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-block {
+ display: block !important;
+ }
+}
+.visible-print-inline {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline {
+ display: inline !important;
+ }
+}
+.visible-print-inline-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline-block {
+ display: inline-block !important;
+ }
+}
+@media print {
+ .hidden-print {
+ display: none !important;
+ }
+}
+.list-item {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.list-item blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.list-header,
+.edit-header {
+ position: fixed;
+ width: 100%;
+ margin-top: 11px;
+ z-index: 1;
+ background-color: #ffffff;
+}
+.list-body {
+ padding-top: 100px;
+}
+.edit-header {
+ padding-top: 10px;
+}
+.edit-body {
+ padding-top: 100px;
+}
+.page-header {
+ padding-left: 20px;
+ z-index: 2;
+}
+.header-rhs {
+ min-width: 226px;
+ min-height: 40px;
+ padding-right: 20px;
+ padding-bottom: 5px;
+ display: block;
+}
+.list-header .header-rhs {
+ margin: 15px 0;
+}
+.fixed-header {
+ position: fixed;
+ width: 100%;
+ margin-top: 11px;
+ z-index: 1;
+}
+.gridStyle {
+ border: 1px solid #d4d4d4;
+ margin: auto;
+ height: 400px;
+}
+.gridStyle .ngTopPanel {
+ background-color: #ffffff;
+}
+.gridStyle .ngHeaderCell {
+ background-color: #e4e4e4;
+}
+.gridStyle .fng-right {
+ text-align: right;
+}
+.gridStyle .fng-left {
+ text-align: left;
+}
+.gridStyle .fng-centre,
+.gridStyle .fng-center {
+ text-align: center;
+}
+.gridStyle .ngTotalCell {
+ font-weight: bold;
+}
+button.form-btn {
+ width: 8em;
+ height: 2em;
+}
+.form-btn-grp {
+ max-width: 17em;
+}
+form.form-horizontal.compact input + .help-block,
+form.form-horizontal.compact select + .help-block,
+form.form-horizontal.compact textarea + .help-block,
+form.form-horizontal.compact .uneditable-input + .help-block,
+form.form-horizontal.compact .input-prepend + .help-block,
+form.form-horizontal.compact .input-append + .help-block {
+ margin-top: 0;
+ margin-bottom: 2px;
+}
+form.form-horizontal.compact hr {
+ margin: 8px 0;
+}
+form .schema-head,
+form .sub-doc,
+form .schema-foot {
+ min-height: 20px;
+ margin-bottom: 20px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+form .schema-head blockquote,
+form .sub-doc blockquote,
+form .schema-foot blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+form .schema-head {
+ margin-top: 8px;
+ margin-bottom: 5px;
+ border: 1px solid #ddd;
+ padding: 4px 180px;
+}
+form .sub-doc {
+ padding: 5px 5px 2px 0;
+ width: 97%;
+ margin-bottom: 3px;
+ position: relative;
+}
+form .sub-doc-btns {
+ position: absolute;
+ right: 8px;
+}
+form .schema-foot {
+ padding: 5px 180px;
+ margin: 5px 0;
+}
+form input[type="checkbox"].ng-invalid-required:before,
+form span:first-child input[type="radio"].ng-invalid-required:before {
+ content: "*";
+ font-weight: bold;
+ color: red;
+ margin-left: -8px;
+}
+form input.ng-invalid-required,
+form select.fng-invalid-required,
+form select.ng-invalid-required,
+form textarea.ng-invalid-required {
+ background-color: rgba(255, 0, 0, 0.1);
+}
+form option {
+ background-color: white;
+}
+form .fng-select2 {
+ width: 220px;
+}
+form .form-inline > .sub-doc {
+ padding: 0 5px;
+ border: none;
+ box-shadow: none;
+}
+a.fng-link,
+span.fng-link {
+ line-height: 30px;
+}
+.form-inline a.fng-link,
+.form-inline span.fng-link {
+ padding: 0 15px;
+}
+span input[type="radio"] {
+ margin: 9px 0 0;
+}
+.global-search {
+ position: relative;
+ float: right;
+}
+.results-container {
+ width: 6000px;
+ z-index: 3;
+ position: absolute;
+ top: 41px;
+ right: 0;
+}
+.search-results {
+ float: right;
+ border: 1px solid gray;
+ -webkit-box-shadow: 10px 10px 10px #888;
+ box-shadow: 10px 10px 10px #888;
+ background: white;
+ padding: 5px;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+.search-results .search-result.focus {
+ color: white;
+}
+.dropdown-menu > .disabled > li,
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ cursor: not-allowed;
+}
+.list-item {
+ padding: 9px;
+ border-radius: 3px;
+ min-height: 40px;
+}
+button.form-btn {
+ font-size: 60%;
+ padding-top: 0.25em;
+}
+.form-horizontal input.input-sm,
+.form-horizontal textarea.input-sm {
+ font-size: 14px;
+ padding: 2px 6px;
+}
+.form-horizontal select.input-sm {
+ font-size: 14px;
+ padding-left: 5px;
+}
+.form-horizontal .checkbox {
+ float: left;
+ padding: 5px 10px 0 6px;
+}
+.form-horizontal .control-label {
+ padding-top: 6px;
+}
+.form-horizontal .bs3-input {
+ padding-left: 0;
+}
+.form-horizontal .help-block {
+ clear: left;
+ bottom-margin: 4px;
+}
+textarea[msd-elastic] {
+ min-height: 25px;
+}
+.fileupload-buttonbar .btn {
+ padding: 5px 8px;
+}
+.page-header {
+ font-family: inherit;
+ font-weight: 500;
+ color: inherit;
+ font-size: 18px;
+ border-bottom: 2px solid inherit;
+ min-height: 50px;
+}
+.fixed-header {
+ background-color: #ffffff;
+}
+@media (max-width: 768px) {
+ .page-body {
+ padding-top: 0;
+ }
+ .page-header {
+ position: static;
+ }
+ .global-search {
+ padding-right: 7px;
+ }
+}
+form.form-horizontal .form-group {
+ margin-left: 0;
+ margin-right: 0;
+}
+form.form-horizontal.compact .form-group {
+ margin-bottom: 2px;
+}
+form .schema-head,
+form .sub-doc,
+form .schema-foot {
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+}
+form .sub-doc {
+ margin-left: 12px;
+}
+form .sub-doc-btns {
+ z-index: 1;
+}
+form .checkbox input[type="checkbox"] {
+ margin-left: -5px;
+}
+form .form-inline > .sub-doc {
+ background-color: #ffffff;
+}
+.search-results .search-result {
+ color: #337ab7;
+}
+.search-results .search-result.focus {
+ background-color: #23527c;
+}
+.form-inline .row {
+ margin-left: 5px;
+ margin-right: 0;
+}
+.form-inline .form-group .input-group {
+ display: table-cell;
+}
+.form-inline .form-group .input-group .input-group-addon {
+ display: none;
+}
+form .tab-content {
+ margin-top: 5px;
+}
+@media (max-width: 767px) {
+ .navbar-form {
+ width: auto;
+ border: 0;
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-form.navbar-right:last-child {
+ margin-right: -15px;
+ }
+ form .schema-head,
+ form .schema-foot {
+ padding: 5px 15px;
+ }
+}
diff --git a/src/client/less/forms-angular-with-bs3.less b/src/client/less/forms-angular-with-bs3.less
new file mode 100644
index 00000000..91ce3aa0
--- /dev/null
+++ b/src/client/less/forms-angular-with-bs3.less
@@ -0,0 +1,3 @@
+@import "../../../node_modules/bootstrap-3-3-7/less/bootstrap.less";
+@import "forms-angular-bs-common.less";
+@import "forms-angular-bs3-specific";
diff --git a/src/client/template/base-analysis.html b/src/client/template/base-analysis.html
new file mode 100644
index 00000000..ea42fd61
--- /dev/null
+++ b/src/client/template/base-analysis.html
@@ -0,0 +1,18 @@
+
diff --git a/src/client/template/base-edit.html b/src/client/template/base-edit.html
new file mode 100644
index 00000000..059412e8
--- /dev/null
+++ b/src/client/template/base-edit.html
@@ -0,0 +1,16 @@
+
diff --git a/src/client/template/base-list.html b/src/client/template/base-list.html
new file mode 100644
index 00000000..cdc94b44
--- /dev/null
+++ b/src/client/template/base-list.html
@@ -0,0 +1,20 @@
+
diff --git a/src/client/template/error-messages.html b/src/client/template/error-messages.html
new file mode 100644
index 00000000..a0b3820e
--- /dev/null
+++ b/src/client/template/error-messages.html
@@ -0,0 +1,7 @@
+A value is required for this field
+Too few characters entered
+Too many characters entered
+That value is too small
+That value is too large
+You need to enter a valid email address
+This field does not match the expected pattern
diff --git a/src/client/template/form-button-bs2.html b/src/client/template/form-button-bs2.html
new file mode 100644
index 00000000..bf6a2cb5
--- /dev/null
+++ b/src/client/template/form-button-bs2.html
@@ -0,0 +1,10 @@
+
diff --git a/src/client/template/form-button-bs3.html b/src/client/template/form-button-bs3.html
new file mode 100644
index 00000000..9b7311fc
--- /dev/null
+++ b/src/client/template/form-button-bs3.html
@@ -0,0 +1,10 @@
+
diff --git a/src/client/template/search-bs2.html b/src/client/template/search-bs2.html
new file mode 100644
index 00000000..0f8b58f4
--- /dev/null
+++ b/src/client/template/search-bs2.html
@@ -0,0 +1,14 @@
+
+
+
+
+ {{result.resourceText}} {{result.text}}
+
+
(plus more - continue typing to narrow down search...)
+
+
+
diff --git a/src/client/template/search-bs3.html b/src/client/template/search-bs3.html
new file mode 100644
index 00000000..d65df0ad
--- /dev/null
+++ b/src/client/template/search-bs3.html
@@ -0,0 +1,14 @@
+
+
+
+
+ {{result.resourceText}} {{result.text}}
+
+
(plus more - continue typing to narrow down search...)
+
+
+
diff --git a/src/server/data_form.ts b/src/server/data_form.ts
new file mode 100644
index 00000000..1d9036e6
--- /dev/null
+++ b/src/server/data_form.ts
@@ -0,0 +1,1233 @@
+'use strict';
+import {Document, Model} from "mongoose";
+
+// This part of forms-angular borrows _very_ heavily from https://github.com/Alexandre-Strzelewicz/angular-bridge
+// (now https://github.com/Unitech/angular-bridge
+
+const _ = require('lodash');
+const util = require('util');
+const extend = require('node.extend');
+const async = require('async');
+
+let debug = false;
+
+interface Resource {
+ resourceName: string;
+ model?: Model; // TODO TS Get rid of the ? here
+ options?: any;
+}
+
+interface ListParams {
+ ref: Boolean; // The object is this a lookup?
+}
+
+interface ListField {
+ field: String;
+ params?: ListParams;
+}
+
+interface IFngPlugin {
+ plugin: (fng: any, expressApp: any, options: FngOptions) => void;
+ options: any;
+}
+
+interface IPluginMap {
+ [key: string]: IFngPlugin;
+}
+
+interface FngOptions {
+ urlPrefix?: string,
+ plugins: IPluginMap
+}
+
+function logTheAPICalls(req, res, next) {
+ void(res);
+ console.log('API : ' + req.method + ' ' + req.url + ' [ ' + JSON.stringify(req.body) + ' ]');
+ next();
+}
+
+function processArgs(options: any, array: Array) : Array{
+ if (options.authentication) {
+ let authArray = _.isArray(options.authentication) ? options.authentication : [options.authentication];
+ for (let i = authArray.length - 1; i >= 0; i--) {
+ array.splice(1, 0, authArray[i]);
+ }
+ }
+ if (debug) {
+ array.splice(1, 0, logTheAPICalls);
+ }
+ array[0] = options.urlPrefix + array[0];
+ return array;
+}
+
+const DataForm = function (mongoose, app, options: FngOptions) {
+ this.app = app;
+ app.locals.formsAngular = app.locals.formsAngular || [];
+ app.locals.formsAngular.push(this);
+ this.mongoose = mongoose;
+ mongoose.set('debug', debug);
+ mongoose.Promise = global.Promise;
+ this.options = _.extend({
+ urlPrefix: '/api/'
+ }, options || {});
+ this.resources = [];
+ this.searchFunc = async.forEach;
+ this.registerRoutes();
+ this.app.get.apply(this.app, processArgs(this.options, ['search', this.searchAll()]));
+ for (let pluginName in this.options.plugins) {
+ let pluginObj: IFngPlugin = this.options.plugins[pluginName];
+ this[pluginName] = pluginObj.plugin(this, processArgs, pluginObj.options);
+ }
+};
+
+module.exports = exports = DataForm;
+
+DataForm.prototype.extractTimestampFromMongoID = function (record: any) : Date {
+ let timestamp = record.toString().substring(0, 8);
+ return new Date(parseInt(timestamp, 16) * 1000);
+};
+
+DataForm.prototype.getListFields = function (resource: Resource, doc: Document, cb) {
+
+ function getFirstMatchingField(keyList, type?) {
+ for (let i = 0; i < keyList.length; i++) {
+ let fieldDetails = resource.model.schema['tree'][keyList[i]];
+ if (fieldDetails.type && (!type || fieldDetails.type.name === type) && keyList[i] !== '_id') {
+ resource.options.listFields = [{field: keyList[i]}];
+ return doc[keyList[i]];
+ }
+ }
+ }
+
+ const that = this;
+ let display = '';
+ let listFields = resource.options.listFields;
+
+ if (listFields) {
+ async.map(listFields, function (aField, cbm) {
+ if (typeof doc[aField.field] !== 'undefined') {
+ if (aField.params) {
+ if (aField.params.ref) {
+ let lookupResource = that.getResource(resource.model.schema['paths'][aField.field].options.ref);
+ if (lookupResource) {
+ let hiddenFields = that.generateHiddenFields(lookupResource, false);
+ hiddenFields.__v = 0;
+ lookupResource.model.findOne({_id: doc[aField.field]}).select(hiddenFields).exec(function (err, doc2) {
+ if (err) {
+ cbm(err);
+ } else {
+ that.getListFields(lookupResource, doc2, cbm);
+ }
+ });
+ }
+ } else if (aField.params.params === 'timestamp') {
+ let date = this.extractTimestampFromMongoID(doc[aField.field]);
+ cbm(null, date.toLocaleDateString() + ' ' + date.toLocaleTimeString());
+ }
+ } else {
+ cbm(null, doc[aField.field]);
+ }
+ } else {
+ cbm(null, '')
+ }
+ }, function (err, results) {
+ if (err) {
+ cb(err);
+ } else {
+ if (results) {
+ cb(err, results.join(' ').trim())
+ } else {
+ console.log('No results ' + listFields);
+ }
+ }
+ });
+ } else {
+ const keyList = Object.keys(resource.model.schema['tree']);
+ // No list field specified - use the first String field,
+ display = getFirstMatchingField(keyList, 'String') ||
+ // and if there aren't any then just take the first field
+ getFirstMatchingField(keyList);
+ cb(null, display.trim());
+ }
+};
+
+/**
+ * Registers all REST routes with the provided `app` object.
+ */
+DataForm.prototype.registerRoutes = function () {
+ const search = 'search/', schema = 'schema/', report = 'report/', resourceName = ':resourceName', id = '/:id';
+ this.app.get.apply(this.app, processArgs(this.options, ['models', this.models()]));
+
+ this.app.get.apply(this.app, processArgs(this.options, [search + resourceName, this.search()]));
+
+ this.app.get.apply(this.app, processArgs(this.options, [schema + resourceName, this.schema()]));
+ this.app.get.apply(this.app, processArgs(this.options, [schema + resourceName + '/:formName', this.schema()]));
+
+ this.app.get.apply(this.app, processArgs(this.options, [report + resourceName, this.report()]));
+ this.app.get.apply(this.app, processArgs(this.options, [report + resourceName + '/:reportName', this.report()]));
+
+ this.app.get.apply(this.app, processArgs(this.options, [resourceName, this.collectionGet()]));
+ this.app.post.apply(this.app, processArgs(this.options, [resourceName, this.collectionPost()]));
+
+ this.app.get.apply(this.app, processArgs(this.options, [resourceName + id, this.entityGet()]));
+ this.app.post.apply(this.app, processArgs(this.options, [resourceName + id, this.entityPut()])); // You can POST or PUT to update data
+ this.app.put.apply(this.app, processArgs(this.options, [resourceName + id, this.entityPut()]));
+ this.app.delete.apply(this.app, processArgs(this.options, [resourceName + id, this.entityDelete()]));
+
+ // return the List attributes for a record - used by select2
+ this.app.get.apply(this.app, processArgs(this.options, [resourceName + id + '/list', this.entityList()]));
+};
+
+DataForm.prototype.newResource = function (model, options) {
+ options = options || {};
+ options.suppressDeprecatedMessage = true;
+ let passModel = model;
+ if (typeof model !== 'function') {
+ passModel = model.model;
+ }
+ this.addResource(passModel.modelName, passModel, options);
+};
+
+// Add a resource, specifying the model and any options.
+// Models may include their own options, which means they can be passed through from the model file
+DataForm.prototype.addResource = function (resourceName, model, options) {
+ let resource: Resource = {
+ resourceName: resourceName,
+ options: options || {}
+ };
+ if (!resource.options.suppressDeprecatedMessage) {
+ console.log('addResource is deprecated - see https://github.com/forms-angular/forms-angular/issues/39');
+ }
+
+ if (typeof model === 'function') {
+ resource.model = model;
+ } else {
+ resource.model = model.model;
+ for (const prop in model) {
+ if (model.hasOwnProperty(prop) && prop !== 'model') {
+ resource.options[prop] = model[prop];
+ }
+ }
+ }
+
+ extend(resource.options, this.preprocess(resource, resource.model.schema['paths'], null));
+
+ if (resource.options.searchImportance) {
+ this.searchFunc = async.forEachSeries;
+ }
+ if (this.searchFunc === async.forEachSeries) {
+ this.resources.splice(_.sortedIndexBy(this.resources, resource, function (obj) {
+ return obj.options.searchImportance || 99;
+ }), 0, resource);
+ } else {
+ this.resources.push(resource);
+ }
+};
+
+DataForm.prototype.getResource = function (name) {
+ return _.find(this.resources, function (resource) {
+ return resource.resourceName === name;
+ });
+};
+
+DataForm.prototype.getResourceFromCollection = function (name) {
+ return _.find(this.resources, function (resource) {
+ return resource.model.collection.collectionName === name;
+ });
+};
+
+DataForm.prototype.internalSearch = function (req, resourcesToSearch, includeResourceInResults, limit, callback) {
+ if (typeof req.query === 'undefined') { req.query = {}; }
+ let searches = [],
+ resourceCount = resourcesToSearch.length,
+ searchFor = req.query.q || '',
+ filter = req.query.f;
+
+ function translate(string, array, context) {
+ if (array) {
+ let translation = _.find(array, function (fromTo) {
+ return fromTo.from === string && (!fromTo.context || fromTo.context === context);
+ });
+ if (translation) {
+ string = translation.to;
+ }
+ }
+ return string;
+ }
+
+ // return a string that determines the sort order of the resultObject
+ function calcResultValue(obj) {
+
+ function padLeft(score: number, reqLength: number, str = '0') {
+ return new Array(1 + reqLength - String(score).length).join(str) + score;
+ }
+
+ let sortString = '';
+ sortString += padLeft(obj.addHits || 9, 1);
+ sortString += padLeft(obj.searchImportance || 99, 2);
+ sortString += padLeft(obj.weighting || 9999, 4);
+ sortString += obj.text;
+ return sortString;
+ }
+
+ if (filter) {
+ filter = JSON.parse(filter);
+ }
+
+ for (let i = 0; i < resourceCount; i++) {
+ let resource = resourcesToSearch[i];
+ if (resourceCount === 1 || resource.options.searchImportance !== false) {
+ let schema = resource.model.schema;
+ let indexedFields = [];
+ for (let j = 0; j < schema._indexes.length; j++) {
+ let attributes = schema._indexes[j][0];
+ let field = Object.keys(attributes)[0];
+ if (indexedFields.indexOf(field) === -1) {
+ indexedFields.push(field);
+ }
+ }
+ for (let path in schema.paths) {
+ if (path !== '_id' && schema.paths.hasOwnProperty(path)) {
+ if (schema.paths[path]._index && !schema.paths[path].options.noSearch) {
+ if (indexedFields.indexOf(path) === -1) {
+ indexedFields.push(path);
+ }
+ }
+ }
+ }
+ if (indexedFields.length === 0) {
+ console.log('ERROR: Searching on a collection with no indexes ' + resource.resourceName);
+ }
+ for (let m = 0; m < indexedFields.length; m++) {
+ searches.push({resource: resource, field: indexedFields[m]});
+ }
+ }
+ }
+ const that = this;
+ let results = [],
+ moreCount = 0,
+ searchCriteria,
+ multiMatchPossible = searchFor.includes(' '),
+ modifiedSearchStr = multiMatchPossible ? searchFor.split(' ').join('|') : searchFor;
+
+ // Removed the logic that preserved spaces when collection was specified because Louise asked me to.
+
+ searchCriteria = {$regex: '^(' + modifiedSearchStr + ')', $options: 'i'};
+
+ this.searchFunc(
+ searches,
+ function (item, cb) {
+ let searchDoc = {};
+ if (filter) {
+ extend(searchDoc, filter);
+ if (filter[item.field]) {
+ delete searchDoc[item.field];
+ let obj1 = {}, obj2 = {};
+ obj1[item.field] = filter[item.field];
+ obj2[item.field] = searchCriteria;
+ searchDoc['$and'] = [obj1, obj2];
+ } else {
+ searchDoc[item.field] = searchCriteria;
+ }
+ } else {
+ searchDoc[item.field] = searchCriteria;
+ }
+
+ // The +60 in the next line is an arbitrary safety zone for situations where items that match the string
+ // in more than one index get filtered out.
+ // TODO : Figure out a better way to deal with this
+ that.filteredFind(item.resource, req, null, searchDoc, item.resource.options.searchOrder, limit + 60, null, function (err, docs) {
+ if (!err && docs && docs.length > 0) {
+ async.map(docs, function (aDoc, cbdoc) {
+ // Do we already have them in the list?
+ let thisId: string = aDoc._id.toString(),
+ resultObject: any,
+ resultPos: number;
+
+ function handleResultsInList() {
+ resultObject.searchImportance = item.resource.options.searchImportance || 99;
+ if (item.resource.options.localisationData) {
+ resultObject.resource = translate(resultObject.resource, item.resource.options.localisationData, 'resource');
+ resultObject.resourceText = translate(resultObject.resourceText, item.resource.options.localisationData, 'resourceText');
+ resultObject.resourceTab = translate(resultObject.resourceTab, item.resource.options.localisationData, 'resourceTab');
+ }
+ results.splice(_.sortedIndexBy(results, resultObject, calcResultValue), 0, resultObject);
+ cbdoc(null);
+ }
+
+ for (resultPos = results.length - 1; resultPos >= 0; resultPos--) {
+ if (results[resultPos].id.toString() === thisId) {
+ break;
+ }
+ }
+ if (resultPos >= 0) {
+ resultObject = {};
+ extend(resultObject, results[resultPos]);
+ // If they have already matched then improve their weighting
+ // TODO: if the search string is B F currently Benjamin Barker scores same as Benjamin Franklin)
+ if (multiMatchPossible) {
+ resultObject.addHits = Math.max((resultObject.addHits || 9) - 1, 1);
+ }
+ // remove it from current position
+ results.splice(resultPos, 1);
+ // and re-insert where appropriate
+ results.splice(_.sortedIndexBy(results, resultObject, calcResultValue), 0, resultObject);
+ cbdoc(null);
+ } else {
+ // Otherwise add them new...
+ // Use special listings format if defined
+ let specialListingFormat = item.resource.options.searchResultFormat;
+ if (specialListingFormat) {
+ resultObject = specialListingFormat.apply(aDoc);
+ handleResultsInList();
+ } else {
+ that.getListFields(item.resource, aDoc, function (err, description) {
+ if (err) {
+ cbdoc(err);
+ } else {
+ resultObject = {
+ id: aDoc._id,
+ weighting: 9999,
+ text: description
+ };
+ if (resourceCount > 1 || includeResourceInResults) {
+ resultObject.resource = resultObject.resourceText = item.resource.resourceName;
+ }
+ handleResultsInList();
+ }
+ });
+ }
+ }
+ }, function (err) {
+ cb(err);
+ });
+ } else {
+ cb(err);
+ }
+ });
+ },
+ function () {
+ // Strip weighting from the results
+ results = _.map(results, function (aResult) {
+ delete aResult.weighting;
+ return aResult;
+ });
+ if (results.length > limit) {
+ moreCount += results.length - limit;
+ results.splice(limit);
+ }
+ callback({results: results, moreCount: moreCount});
+ }
+ );
+};
+
+DataForm.prototype.search = function () {
+ return _.bind(function (req, res, next) {
+ if (!(req.resource = this.getResource(req.params.resourceName))) {
+ return next();
+ }
+
+ this.internalSearch(req, [req.resource], false, 10, function (resultsObject) {
+ res.send(resultsObject);
+ });
+ }, this);
+};
+
+DataForm.prototype.searchAll = function () {
+ return _.bind(function (req, res) {
+ this.internalSearch(req, this.resources, true, 10, function (resultsObject) {
+ res.send(resultsObject);
+ });
+ }, this);
+};
+
+DataForm.prototype.models = function () {
+
+ const that = this;
+
+ return function (req, res) {
+// TODO: Make this less wasteful - we only need to send the resourceNames of the resources
+ // Check for optional modelFilter and call it with the request and current list. Otherwise just return the list.
+ res.send(that.options.modelFilter ? that.options.modelFilter.call(null, req, that.resources) : that.resources);
+
+ };
+};
+
+
+DataForm.prototype.renderError = function (err, redirectUrl, req, res) {
+ if (typeof err === 'string') {
+ res.send(err);
+ } else {
+ res.send(err.message);
+ }
+};
+
+DataForm.prototype.redirect = function (address, req, res) {
+ res.send(address);
+};
+
+DataForm.prototype.applySchemaSubset = function (vanilla, schema) {
+ let outPath;
+ if (schema) {
+ outPath = {};
+ for (let fld in schema) {
+ if (schema.hasOwnProperty(fld)) {
+ if (!vanilla[fld]) {
+ throw new Error('No such field as ' + fld + '. Is it part of a sub-doc? If so you need the bit before the period.');
+ }
+ outPath[fld] = vanilla[fld];
+ if (vanilla[fld].schema) {
+ outPath[fld].schema = this.applySchemaSubset(outPath[fld].schema, schema[fld].schema);
+ }
+ outPath[fld].options = outPath[fld].options || {};
+ for (let override in schema[fld]) {
+ if (schema[fld].hasOwnProperty(override)) {
+ if (!outPath[fld].options.form) {
+ outPath[fld].options.form = {};
+ }
+ outPath[fld].options.form[override] = schema[fld][override];
+ }
+ }
+ }
+ }
+ } else {
+ outPath = vanilla;
+ }
+ return outPath;
+};
+
+DataForm.prototype.preprocess = function (resource: Resource, paths, formSchema) {
+ let outPath = {},
+ hiddenFields = [],
+ listFields = [];
+
+ if (resource && resource.options && resource.options.idIsList) {
+ paths['_id'].options = paths['_id'].options || {};
+ paths['_id'].options.list = resource.options.idIsList;
+ }
+ for (let element in paths) {
+ if (paths.hasOwnProperty(element) && element !== '__v') {
+ // check for schemas
+ if (paths[element].schema) {
+ let subSchemaInfo = this.preprocess(null, paths[element].schema.paths);
+ outPath[element] = {schema: subSchemaInfo.paths};
+ if (paths[element].options.form) {
+ outPath[element].options = {form: extend(true, {}, paths[element].options.form)};
+ }
+ } else {
+ // check for arrays
+ let realType = paths[element].caster ? paths[element].caster : paths[element];
+ if (!realType.instance) {
+
+ if (realType.options.type) {
+ let type = realType.options.type(),
+ typeType = typeof type;
+
+ if (typeType === 'string') {
+ realType.instance = (!isNaN(Date.parse(type))) ? 'Date' : 'String';
+ } else {
+ realType.instance = typeType;
+ }
+ }
+ }
+ outPath[element] = extend(true, {}, paths[element]);
+ if (paths[element].options.secure) {
+ hiddenFields.push(element);
+ }
+ if (paths[element].options.match) {
+ outPath[element].options.match = paths[element].options.match.source;
+ }
+ let schemaListInfo: any = paths[element].options.list;
+ if (schemaListInfo) {
+ let listFieldInfo: ListField = {field: element};
+ if (typeof schemaListInfo === 'object' && Object.keys(schemaListInfo).length > 0) {
+ listFieldInfo.params = schemaListInfo;
+ }
+ listFields.push(listFieldInfo);
+ }
+ }
+ }
+ }
+ outPath = this.applySchemaSubset(outPath, formSchema);
+ let returnObj: any = {paths: outPath};
+ if (hiddenFields.length > 0) {
+ returnObj.hide = hiddenFields;
+ }
+ if (listFields.length > 0) {
+ returnObj.listFields = listFields;
+ }
+ return returnObj;
+};
+
+DataForm.prototype.schema = function () {
+ return _.bind(function (req, res) {
+ if (!(req.resource = this.getResource(req.params.resourceName))) {
+ return res.status(404).end();
+ }
+ let formSchema = null;
+ if (req.params.formName) {
+ formSchema = req.resource.model.schema.statics['form'](req.params.formName);
+ }
+ let paths = this.preprocess(req.resource, req.resource.model.schema.paths, formSchema).paths;
+ res.send(paths);
+ }, this);
+};
+
+DataForm.prototype.report = function () {
+ return _.bind(function (req, res, next) {
+ if (!(req.resource = this.getResource(req.params.resourceName))) {
+ return next();
+ }
+
+ const self = this;
+ if (typeof req.query === 'undefined') { req.query = {}; }
+
+ let reportSchema;
+
+ if (req.params.reportName) {
+ reportSchema = req.resource.model.schema.statics['report'](req.params.reportName, req);
+ } else if (req.query.r) {
+ switch (req.query.r[0]) {
+ case '[':
+ reportSchema = {pipeline: JSON.parse(req.query.r)};
+ break;
+ case '{':
+ reportSchema = JSON.parse(req.query.r);
+ break;
+ default:
+ return self.renderError(new Error('Invalid "r" parameter'), null, req, res, next);
+ }
+ } else {
+ let fields = {};
+ for (let key in req.resource.model.schema.paths) {
+ if (req.resource.model.schema.paths.hasOwnProperty(key)) {
+ if (key !== '__v' && !req.resource.model.schema.paths[key].options.secure) {
+ if (key.indexOf('.') === -1) {
+ fields[key] = 1;
+ }
+ }
+ }
+ }
+ reportSchema = {
+ pipeline: [
+ {$project: fields}
+ ], drilldown: req.params.resourceName + '/|_id|/edit'
+ };
+ }
+
+ // Replace parameters in pipeline
+ let schemaCopy: any = {};
+ extend(schemaCopy, reportSchema);
+ schemaCopy.params = schemaCopy.params || [];
+
+ self.reportInternal(req, req.resource, schemaCopy, function (err, result) {
+ if (err) {
+ self.renderError(err, null, req, res, next);
+ } else {
+ res.send(result);
+ }
+ });
+ }, this);
+};
+
+DataForm.prototype.hackVariablesInPipeline = function (runPipeline) {
+ for (let pipelineSection = 0; pipelineSection < runPipeline.length; pipelineSection++) {
+ if (runPipeline[pipelineSection]['$match']) {
+ this.hackVariables(runPipeline[pipelineSection]['$match']);
+ }
+ }
+};
+
+DataForm.prototype.hackVariables = function (obj) {
+ // Replace variables that cannot be serialised / deserialised. Bit of a hack, but needs must...
+ // Anything formatted 1800-01-01T00:00:00.000Z or 1800-01-01T00:00:00.000+0000 is converted to a Date
+ // Only handles the cases I need for now
+ // TODO: handle arrays etc
+ for (const prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ if (typeof obj[prop] === 'string') {
+ const dateTest = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3})(Z|[+ -]\d{4})$/.exec(obj[prop]);
+ if (dateTest) {
+ obj[prop] = new Date(dateTest[1] + 'Z');
+ } else {
+ const objectIdTest = /^([0-9a-fA-F]{24})$/.exec(obj[prop]);
+ if (objectIdTest) {
+ obj[prop] = new this.mongoose.Schema.Types.ObjectId(objectIdTest[1]);
+ }
+ }
+ } else if (_.isObject(obj[prop])) {
+ this.hackVariables(obj[prop]);
+ }
+ }
+ }
+};
+
+DataForm.prototype.reportInternal = function (req, resource, schema, callback) {
+ let runPipeline: any;
+ let self = this;
+ if (typeof req.query === 'undefined') { req.query = {}; }
+
+ self.doFindFunc(req, resource, function (err, queryObj) {
+ if (err) {
+ return 'There was a problem with the findFunc for model';
+ } else {
+ // Bit crap here switching back and forth to string
+ runPipeline = JSON.stringify(schema.pipeline);
+ for (let param in req.query) {
+ if (req.query[param]) {
+ if (param !== 'r') { // we don't want to copy the whole report schema (again!)
+ schema.params[param].value = req.query[param];
+ }
+ }
+ }
+
+ // Replace parameters with the value
+ if (runPipeline) {
+ runPipeline = runPipeline.replace(/\"\(.+?\)\"/g, function (match) {
+ let sparam = schema.params[match.slice(2, -2)];
+ if (sparam.type === 'number') {
+ return sparam.value;
+ } else if (_.isObject(sparam.value)) {
+ return JSON.stringify(sparam.value);
+ } else if (sparam.value[0] === '{') {
+ return sparam.value;
+ } else {
+ return '"' + sparam.value + '"';
+ }
+ });
+ }
+
+ // Don't send the 'secure' fields
+ let hiddenFields = self.generateHiddenFields(resource, false);
+ for (const hiddenField in hiddenFields) {
+ if (hiddenFields.hasOwnProperty(hiddenField)) {
+ if (runPipeline.indexOf(hiddenField) !== -1) {
+ return callback('You cannot access ' + hiddenField);
+ }
+ }
+ }
+
+ runPipeline = JSON.parse(runPipeline);
+ self.hackVariablesInPipeline(runPipeline);
+
+ // Add the findFunc query to the pipeline
+ if (queryObj) {
+ runPipeline.unshift({$match: queryObj});
+ }
+
+ let toDo: any = {
+ runAggregation: function (cb) {
+ resource.model.aggregate(runPipeline, cb);
+ }
+ };
+
+ let translations = []; // array of form {ref:'lookupname',translations:[{value:xx, display:' '}]}
+ // if we need to do any column translations add the function to the tasks list
+ if (schema.columnTranslations) {
+ toDo.applyTranslations = ['runAggregation', function (results: any, cb) {
+
+ function doATranslate(column, theTranslation) {
+ results['runAggregation'].forEach(function (resultRow) {
+ let valToTranslate = resultRow[column.field];
+ valToTranslate = (valToTranslate ? valToTranslate.toString() : '');
+ let thisTranslation = _.find(theTranslation.translations, function (option) {
+ return valToTranslate === option.value.toString();
+ });
+ resultRow[column.field] = thisTranslation ? thisTranslation.display : ' * Missing columnTranslation * ';
+ });
+ }
+
+ schema.columnTranslations.forEach(function (columnTranslation) {
+ if (columnTranslation.translations) {
+ doATranslate(columnTranslation, columnTranslation);
+ }
+ if (columnTranslation.ref) {
+ let theTranslation = _.find(translations, function (translation) {
+ return (translation.ref === columnTranslation.ref);
+ });
+ if (theTranslation) {
+ doATranslate(columnTranslation, theTranslation);
+ } else {
+ cb('Invalid ref property of ' + columnTranslation.ref + ' in columnTranslations ' + columnTranslation.field);
+ }
+ }
+ });
+ cb(null, null);
+ }];
+
+ let callFuncs = false;
+ for (let i = 0; i < schema.columnTranslations.length; i++) {
+ let thisColumnTranslation = schema.columnTranslations[i];
+
+ if (thisColumnTranslation.field) {
+ // if any of the column translations are adhoc funcs, set up the tasks to perform them
+ if (thisColumnTranslation.fn) {
+ callFuncs = true;
+ }
+
+ // if this column translation is a "ref", set up the tasks to look up the values and populate the translations
+ if (thisColumnTranslation.ref) {
+ let lookup = self.getResource(thisColumnTranslation.ref);
+ if (lookup) {
+ if (!toDo[thisColumnTranslation.ref]) {
+ let getFunc = function (ref) {
+ let lookup = ref;
+ return function (cb) {
+ let translateObject = {ref: lookup.resourceName, translations: []};
+ translations.push(translateObject);
+ lookup.model.find({}, {}, {lean: true}, function (err, findResults) {
+ if (err) {
+ cb(err);
+ } else {
+ // TODO - this ref func can probably be done away with now that list fields can have ref
+ let j = 0;
+ async.whilst(
+ function () {
+ return j < findResults.length;
+ },
+ function (cbres) {
+ let theResult = findResults[j];
+ translateObject.translations[j] = translateObject.translations[j] || {};
+ let theTranslation = translateObject.translations[j];
+ j++;
+ self.getListFields(lookup, theResult, function (err, description) {
+ if (err) {
+ cbres(err);
+ } else {
+ theTranslation.value = theResult._id;
+ theTranslation.display = description;
+ cbres(null);
+ }
+ })
+ },
+ cb
+ );
+ }
+ });
+ };
+ };
+ toDo[thisColumnTranslation.ref] = getFunc(lookup);
+ toDo.applyTranslations.unshift(thisColumnTranslation.ref); // Make sure we populate lookup before doing translation
+ }
+ } else {
+ return callback('Invalid ref property of ' + thisColumnTranslation.ref + ' in columnTranslations ' + thisColumnTranslation.field);
+ }
+ }
+ if (!thisColumnTranslation.translations && !thisColumnTranslation.ref && !thisColumnTranslation.fn) {
+ return callback('A column translation needs a ref, fn or a translations property - ' + thisColumnTranslation.field + ' has neither');
+ }
+ } else {
+ return callback('A column translation needs a field property');
+ }
+ }
+ if (callFuncs) {
+ toDo['callFunctions'] = ['runAggregation', function (results, cb) {
+ async.each(results.runAggregation, function (row, cb) {
+ for (let i = 0; i < schema.columnTranslations.length; i++) {
+ let thisColumnTranslation = schema.columnTranslations[i];
+
+ if (thisColumnTranslation.fn) {
+ thisColumnTranslation.fn(row, cb);
+ }
+ }
+ }, function () {
+ cb(null);
+ });
+ }];
+ toDo.applyTranslations.unshift('callFunctions'); // Make sure we do function before translating its result
+ }
+ }
+
+ async.auto(toDo, function (err, results) {
+ if (err) {
+ callback(err);
+ } else {
+ // TODO: Could loop through schema.params and just send back the values
+ callback(null, {success: true, schema: schema, report: results.runAggregation, paramsUsed: schema.params});
+ }
+ });
+ }
+ });
+};
+
+DataForm.prototype.saveAndRespond = function (req, res, hiddenFields) {
+
+ function internalSave(doc) {
+ doc.save(function (err, doc2) {
+ if (err) {
+ let err2: any = {status: 'err'};
+ if (!err.errors) {
+ err2.message = err.message;
+ } else {
+ extend(err2, err);
+ }
+ if (debug) {
+ console.log('Error saving record: ' + JSON.stringify(err2));
+ }
+ res.status(400).send(err2);
+ } else {
+ doc2 = doc2.toObject();
+ for (const hiddenField in hiddenFields) {
+ if (hiddenFields.hasOwnProperty(hiddenField) && hiddenFields[hiddenField]) {
+ let parts = hiddenField.split('.');
+ let lastPart = parts.length - 1;
+ let target = doc2;
+ for (let i = 0; i < lastPart; i++) {
+ if (target.hasOwnProperty(parts[i])) {
+ target = target[parts[i]];
+ }
+ }
+ if (target.hasOwnProperty(parts[lastPart])) {
+ delete target[parts[lastPart]];
+ }
+ }
+ }
+ res.send(doc2);
+ }
+ });
+ }
+
+ let doc = req.doc;
+ if (typeof req.resource.options.onSave === 'function') {
+
+ req.resource.options.onSave(doc, req, function (err) {
+ if (err) {
+ throw err;
+ }
+ internalSave(doc);
+ });
+ } else {
+ internalSave(doc);
+ }
+};
+
+/**
+ * All entities REST functions have to go through this first.
+ */
+DataForm.prototype.processCollection = function (req) {
+ req.resource = this.getResource(req.params.resourceName);
+};
+
+/**
+ * Renders a view with the list of docs, which may be modified by query parameters
+ */
+DataForm.prototype.collectionGet = function () {
+ return _.bind(function (req, res, next) {
+ this.processCollection(req);
+ if (!req.resource) {
+ return next();
+ }
+ if (typeof req.query === 'undefined') { req.query = {}; }
+
+ try {
+ const aggregationParam = req.query.a ? JSON.parse(req.query.a) : null;
+ const findParam = req.query.f ? JSON.parse(req.query.f) : {};
+ const limitParam = req.query.l ? JSON.parse(req.query.l) : 0;
+ const skipParam = req.query.s ? JSON.parse(req.query.s) : 0;
+ const orderParam = req.query.o ? JSON.parse(req.query.o) : req.resource.options.listOrder;
+
+ // Dates in aggregation must be Dates
+ if (aggregationParam) {
+ this.hackVariablesInPipeline(aggregationParam);
+ }
+
+ const self = this;
+
+ this.filteredFind(req.resource, req, aggregationParam, findParam, orderParam, limitParam, skipParam, function (err, docs) {
+ if (err) {
+ return self.renderError(err, null, req, res, next);
+ } else {
+ res.send(docs);
+ }
+ });
+ } catch (e) {
+ res.send(e);
+ }
+ }, this);
+};
+
+DataForm.prototype.doFindFunc = function (req, resource, cb) {
+ if (resource.options.findFunc) {
+ resource.options.findFunc(req, cb);
+ } else {
+ cb(null);
+ }
+};
+
+DataForm.prototype.filteredFind = function (resource, req, aggregationParam, findParam, sortOrder, limit, skip, callback) {
+
+ const that = this;
+ let hiddenFields = this.generateHiddenFields(resource, false);
+
+ function doAggregation(cb) {
+ if (aggregationParam) {
+ resource.model.aggregate(aggregationParam, function (err, aggregationResults) {
+ if (err) {
+ throw err;
+ } else {
+ cb(_.map(aggregationResults, function (obj) {
+ return obj._id;
+ }));
+ }
+ });
+ } else {
+ cb([]);
+ }
+ }
+
+ doAggregation(function (idArray) {
+ if (aggregationParam && idArray.length === 0) {
+ callback(null, []);
+ } else {
+ that.doFindFunc(req, resource, function (err, queryObj) {
+ if (err) {
+ callback(err);
+ } else {
+ let query = resource.model.find(queryObj);
+ if (idArray.length > 0) {
+ query = query.where('_id').in(idArray);
+ }
+ query = query.find(findParam).select(hiddenFields);
+ if (limit) {
+ query = query.limit(limit);
+ }
+ if (skip) {
+ query = query.skip(skip);
+ }
+ if (sortOrder) {
+ query = query.sort(sortOrder);
+ }
+ query.exec(callback);
+ }
+ });
+ }
+ });
+};
+
+DataForm.prototype.collectionPost = function () {
+ return _.bind(function (req, res, next) {
+ this.processCollection(req);
+ if (!req.resource) {
+ next();
+ return;
+ }
+ if (!req.body) {
+ throw new Error('Nothing submitted.');
+ }
+
+ let cleansedBody = this.cleanseRequest(req);
+ req.doc = new req.resource.model(cleansedBody);
+
+ this.saveAndRespond(req, res);
+ }, this);
+};
+
+/**
+ * Generate an object of fields to not expose
+ **/
+DataForm.prototype.generateHiddenFields = function (resource, state) {
+ let hiddenFields = {};
+
+ if (resource.options['hide'] !== undefined) {
+ resource.options.hide.forEach(function (dt) {
+ hiddenFields[dt] = state;
+ });
+ }
+ return hiddenFields;
+};
+
+/** Sec issue
+ * Cleanse incoming data to avoid overwrite and POST request forgery
+ * (name may seem weird but it was in French, so it is some small improvement!)
+ */
+DataForm.prototype.cleanseRequest = function (req) {
+ let reqData = req.body,
+ resource = req.resource;
+
+ delete reqData.__v; // Don't mess with Mongoose internal field (https://github.com/LearnBoost/mongoose/issues/1933)
+ if (typeof resource.options['hide'] === 'undefined') {
+ return reqData;
+ }
+ let hiddenFields = resource.options.hide;
+
+ _.each(reqData, function (num, key) {
+ _.each(hiddenFields, function (fi) {
+ if (fi === key) {
+ delete reqData[key];
+ }
+ });
+ });
+
+ return reqData;
+};
+
+DataForm.prototype.generateQueryForEntity = function (req, resource, id, cb) {
+ let hiddenFields = this.generateHiddenFields(resource, false);
+ hiddenFields.__v = 0;
+
+ this.doFindFunc(req, resource, function (err, queryObj) {
+ if (err) {
+ cb(err);
+ } else {
+ let idSel = {_id: id};
+ let crit = queryObj ? extend(queryObj, idSel) : idSel;
+ cb(null, resource.model.findOne(crit).select(hiddenFields));
+ }
+ });
+};
+
+/*
+ * Entity request goes there first
+ * It retrieves the resource
+ */
+DataForm.prototype.processEntity = function (req, res, next) {
+ if (!(req.resource = this.getResource(req.params.resourceName))) {
+ next();
+ return;
+ }
+ this.generateQueryForEntity(req, req.resource, req.params.id, function (err, query) {
+ if (err) {
+ return res.send({
+ success: false,
+ err: util.inspect(err)
+ });
+ } else {
+ query.exec(function (err, doc) {
+ if (err) {
+ return res.send({
+ success: false,
+ err: util.inspect(err)
+ });
+ }
+ else if (doc == null) {
+ return res.send({
+ success: false,
+ err: 'Record not found'
+ });
+ }
+ req.doc = doc;
+ next();
+ });
+ }
+ });
+};
+
+/**
+ * Gets a single entity
+ *
+ * @return {Function} The function to use as route
+ */
+DataForm.prototype.entityGet = function () {
+ return _.bind(function (req, res, next) {
+
+ this.processEntity(req, res, function () {
+ if (!req.resource) {
+ return next();
+ }
+ return res.send(req.doc);
+ });
+ }, this);
+};
+
+DataForm.prototype.replaceHiddenFields = function (record, data) {
+ const self = this;
+ if (record) {
+ record._replacingHiddenFields = true;
+ _.each(data, function (value, name) {
+ if (_.isObject(value)) {
+ self.replaceHiddenFields(record[name], value);
+ } else {
+ record[name] = value;
+ }
+ });
+ delete record._replacingHiddenFields;
+ }
+};
+
+DataForm.prototype.entityPut = function () {
+ return _.bind(function (req, res, next) {
+ const that = this;
+
+ this.processEntity(req, res, function () {
+ if (!req.resource) {
+ next();
+ return;
+ }
+
+ if (!req.body) {
+ throw new Error('Nothing submitted.');
+ }
+ let cleansedBody = that.cleanseRequest(req);
+
+ // Merge
+ _.each(cleansedBody, function (value, name) {
+ req.doc[name] = (value === '') ? undefined : value;
+ });
+
+ if (req.resource.options.hide !== undefined) {
+ let hiddenFields = that.generateHiddenFields(req.resource, true);
+ hiddenFields._id = false;
+ req.resource.model.findById(req.doc._id, hiddenFields, {lean: true}, function (err, data) {
+ that.replaceHiddenFields(req.doc, data);
+ that.saveAndRespond(req, res, hiddenFields);
+ });
+ } else {
+ that.saveAndRespond(req, res);
+ }
+ });
+ }, this);
+};
+
+DataForm.prototype.entityDelete = function () {
+ return _.bind(function (req, res, next) {
+
+ function internalRemove(doc) {
+ doc.remove(function (err) {
+ if (err) {
+ return res.send({success: false});
+ }
+ return res.send({success: true});
+ });
+ }
+
+ this.processEntity(req, res, function () {
+ if (!req.resource) {
+ next();
+ return;
+ }
+
+ let doc = req.doc;
+ if (typeof req.resource.options.onRemove === 'function') {
+
+ req.resource.options.onRemove(doc, req, function (err) {
+ if (err) {
+ throw err;
+ }
+ internalRemove(doc);
+ });
+ } else {
+ internalRemove(doc);
+ }
+
+ });
+ }, this);
+};
+
+DataForm.prototype.entityList = function () {
+ return _.bind(function (req, res, next) {
+ const that = this;
+ this.processEntity(req, res, function () {
+ if (!req.resource) {
+ return next();
+ }
+ that.getListFields(req.resource, req.doc, function (err, display) {
+ if (err) {
+ return res.status(500).send(err);
+ } else {
+ return res.send({list: display});
+ }
+ })
+ });
+ }, this);
+};
+
diff --git a/test/api/CRUD-APISpec.js b/test/api/CRUD-APISpec.js
new file mode 100644
index 00000000..147a3536
--- /dev/null
+++ b/test/api/CRUD-APISpec.js
@@ -0,0 +1,540 @@
+'use strict';
+
+var assert = require('assert');
+var formsAngular = require('../../dist/server/data_form.js');
+var express = require('express');
+var async = require('async');
+var path = require('path');
+var fs = require('fs');
+var exec = require('child_process').exec;
+var mongoose = require('mongoose');
+
+describe('API', function () {
+
+ var fng, app;
+
+ before(function (done) {
+ app = express();
+
+ fng = new (formsAngular)(mongoose, app, {urlPrefix: '/api/'});
+
+ mongoose.connect('mongodb://localhost/forms-ng_test', {useMongoClient: true});
+ mongoose.connection.on('error', function () {
+ console.error('connection error', arguments);
+ });
+
+ mongoose.connection.on('open', function () {
+ // Bootstrap models
+ var modelsPath = path.join(__dirname, '/models');
+ fs.readdirSync(modelsPath).forEach(function (file) {
+ var fname = modelsPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ fng.addResource(file.slice(0, -3), require(fname), {suppressDeprecatedMessage: true});
+ }
+ });
+ });
+
+ // Import test data
+ var dataPath = path.join(__dirname, 'data');
+ async.each(fs.readdirSync(dataPath), function (file, callback) {
+ var fname = dataPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ exec('mongoimport --db forms-ng_test --drop --collection ' + file.slice(0, 1) + 's --jsonArray < ' + fname, callback);
+ }
+ }, function (err) {
+ if (err) {
+ console.log('Problem importing test data ' + err.message);
+ } else {
+ done();
+ }
+ });
+ });
+
+ after(function (done) {
+ mongoose.connection.db.dropDatabase(function () {
+ mongoose.disconnect(function () {
+ done();
+ });
+ });
+ });
+
+ describe('data read', function () {
+
+ var aData, aPtr, bData, bPtr;
+
+ function getCollection(model, cb) {
+ var mockReq = {
+ url: '/' + model,
+ params : {resourceName : model}
+ };
+ var mockRes = {
+ send: function (data) {
+ cb(null, data);
+ }
+ };
+ fng.collectionGet()(mockReq, mockRes);
+ }
+
+ before(function (done) {
+ async.auto(
+ {
+ aData: function (cb) { getCollection('a_unadorned_mongoose', cb); },
+ bData: function (cb) { getCollection('b_using_options', cb); }
+ },
+ function (err, results) {
+ if (err) { throw err; }
+ aData = results['aData'];
+ aPtr = aData.find(function(obj) {return obj.surname === 'TestPerson1'});
+ bData = results['bData'];
+ bPtr = bData.find(function(obj) {return obj.surname === 'IsAccepted1'});
+ done();
+ }
+ );
+ });
+
+ it('should send the right number of records', function () {
+ assert.equal(aData.length, 2);
+ });
+
+ it('should send the all the fields of mongoose schema', function () {
+ assert(aPtr.surname, 'must send surname');
+ assert(aPtr.forename, 'must send forename');
+ assert(aPtr.weight, 'must send weight');
+ assert(aPtr.eyeColour, 'must send eyeColour');
+ assert(aPtr.dateOfBirth, 'must send dob');
+ assert.equal(aPtr.accepted, false, 'must send accepted');
+ });
+
+ it('should filter out records that do not match the find func', function () {
+ assert.equal(bData.length, 2);
+ });
+
+ it('should not send secure fields of a modified schema', function () {
+ assert(bPtr.surname, 'Must send surname');
+ assert(bPtr.forename, 'Must send forename');
+ assert.equal(Object.keys(bPtr).indexOf('login'), -1, 'Must not send secure login field');
+ assert.equal(Object.keys(bPtr).indexOf('passwordHash'), -1, 'Must not send secure password hash field');
+ assert(bPtr.email, 'Must send email');
+ assert(bPtr.weight, 'Must send weight');
+ assert(bPtr.accepted, 'Must send accepted');
+ assert(bPtr.interviewScore, 'Must send interview score');
+ assert(bPtr.freeText, 'Must send freetext');
+ });
+
+ it('should not send secure fields of a modified subschema', function () {
+ assert(bPtr.address.line1, 'Must send line1');
+ assert(bPtr.address.town, 'Must send town');
+ assert(bPtr.address.postcode, 'Must send postcode');
+ assert.equal(Object.keys(bPtr).indexOf('address.surveillance'), -1, 'Must not send secure surveillance field');
+ });
+
+ });
+
+ describe('data update', function () {
+
+ var id;
+
+ it('should create a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options',
+ params: {resourceName: 'b_using_options'},
+ body: {'surname': 'TestCreate', 'accepted': true},
+ ip: '192.168.99.99'
+ };
+ var mockRes = {
+ send: function (data) {
+ assert(data._id, 'Must return the id');
+ id = data._id;
+ assert.equal(data.surname, 'TestCreate');
+ assert.equal(data.accepted, true);
+ assert.equal(data.ipAddress, '192.168.99.99');
+ done();
+ }
+ };
+ fng.collectionPost()(mockReq, mockRes);
+ });
+
+ it('should update a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options/' + id,
+ params: {resourceName: 'b_using_options', id: id},
+ body: {'forename': 'Alfie'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.forename, 'Alfie');
+ done();
+ }
+ };
+ fng.entityPut()(mockReq, mockRes);
+ });
+
+ it('should delete a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options/' + id,
+ params: {resourceName: 'b_using_options', id: id}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert(data.success, 'Failed to delete document');
+ done();
+ }
+ };
+ fng.entityDelete()(mockReq, mockRes);
+ });
+
+ });
+
+ describe('Secure fields', function () {
+
+ it('should not be transmitted in a listing', function (done) {
+ var mockReq = {
+ url: 'c_subdoc_example',
+ params: {
+ resourceName: 'c_subdoc_example',
+ id: '519aaaaab320153869b175e0'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.length, 2);
+ var dataPtr = data.find(function(obj) {return obj.surname === 'Anderson'});
+ assert.equal(dataPtr.passwordHash, undefined);
+ assert.notEqual(dataPtr.interview.score, undefined);
+ assert.equal(dataPtr.interview.interviewHash, undefined);
+ done();
+ }
+ };
+ fng.collectionGet()(mockReq, mockRes);
+ });
+
+ it('should not be transmitted in an entity get', function (done) {
+ var mockReq = {
+ url: 'c_subdoc_example/519aaaaab320153869b175e0',
+ params: {
+ resourceName: 'c_subdoc_example',
+ id: '519aaaaab320153869b175e0'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.surname, 'Anderson');
+ assert.equal(data.passwordHash, undefined);
+ assert.notEqual(data.interview.score, undefined);
+ assert.equal(data.interview.interviewHash, undefined);
+ done();
+ }
+ };
+ fng.entityGet()(mockReq, mockRes);
+ });
+
+
+ it('should not be overwritten by nulls and should not be transmitted on update', function (done) {
+ var mockReq = {
+ url: '/c_subdoc_example/519aaaaab320153869b175e0',
+ params: {resourceName: 'c_subdoc_example', id: '519aaaaab320153869b175e0'},
+ body: {'surname': 'Anderson', 'forename': 'John', 'weight': 124, 'hairColour': 'Brown', 'accepted': true, 'interview': { 'score': 97, 'date': '23 Mar 2013' }}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.weight, 124);
+ assert.equal(data.passwordHash, undefined);
+ assert.equal(data.interview.score, 97);
+ assert.equal(data.interview.interviewHash, undefined);
+ var resource = fng.getResource('c_subdoc_example');
+ resource.model.findById('519aaaaab320153869b175e0', function (err, dataOnDisk) {
+ if (err) { throw err; }
+ assert.equal(dataOnDisk.weight, 124);
+ assert.equal(dataOnDisk.passwordHash, 'top secret');
+ assert.equal(dataOnDisk.interview.score, 97);
+ assert.equal(dataOnDisk.interview.interviewHash, 'you think I would tell you?');
+ done();
+ });
+ }
+ };
+ fng.entityPut()(mockReq, mockRes);
+ });
+ });
+
+ describe('Filtering records', function () {
+
+ var id;
+
+ it('should create a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options',
+ params: {resourceName: 'b_using_options'},
+ body: {'surname': 'TestCreate', 'forename': 'Alice', 'accepted': false},
+ ip: '192.168.99.99'
+ };
+ var mockRes = {
+ send: function (data) {
+ assert(data._id, 'Must return the id');
+ id = data._id;
+ assert.equal(data.surname, 'TestCreate');
+ assert.equal(data.accepted, false);
+ assert.equal(data.ipAddress, '192.168.99.99');
+ done();
+ }
+ };
+ fng.collectionPost()(mockReq, mockRes);
+ });
+
+ it('should not update a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options/' + id,
+ params: {resourceName: 'b_using_options', id: id},
+ body: {'forename': 'Alfie'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.success, false);
+ done();
+ }
+ };
+ fng.entityPut()(mockReq, mockRes);
+ });
+
+ it('should not delete a record', function (done) {
+ var mockReq = {
+ url: '/b_using_options/' + id,
+ params: {resourceName: 'b_using_options', id: id}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert(!data.success, 'Was allowed to delete document');
+ done();
+ }
+ };
+ fng.entityDelete()(mockReq, mockRes);
+ });
+
+ });
+
+ describe('Search API', function () {
+
+ it('should find a single match', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'IsAccepted1'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 1);
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+ it('should find two matches', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'Test'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 2);
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+
+ it('should not find records that do not meet find function', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'Jones'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 0);
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+ it('shoucd ..ld not find records indexed on a no-search field', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'ReportingIndex'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 0);
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+
+ it('should support searchOrder option', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'Smi'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 10);
+ assert.equal(data.results[0].text, 'Smith00 John00');
+ assert.equal(data.results[9].text, 'Smith10 John10');
+ assert.equal(JSON.stringify(data.results).indexOf('John07'), -1);
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+ it('should find a record from a partial initial string', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'ann'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 1);
+ assert.equal(data.results[0].id, '51c583d5b5c51226db418f16');
+ assert.equal(data.results[0].resource, 'f_nested_schema');
+ assert.equal(data.results[0].resourceText, 'Exams');
+ assert.equal(data.results[0].text, 'Smith, Anne');
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+ it('should find a record from multiple partial initial strings', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'smi john04'
+ },
+ route: {path : '/api/search'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.notEqual(data.moreCount, 0);
+ assert.equal(data.results[0].text, 'Smith04 John04'); // Double hit should come first
+ assert.equal(data.results[1].text, 'Smith00 John00'); // normal weighting
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+ it('should not repeat a record in the results', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'smith04 john04'
+ },
+ route: {path : '/api/search'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 1);
+ assert.equal(data.results[0].text, 'Smith04 John04');
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+
+
+ it('should support searchResultFormat option', function (done) {
+ var mockReq = {
+ url: '/search',
+ query: {
+ q:'Br'
+ },
+ route: {path : '/api/search'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.results.length, 2);
+ assert.equal(data.results[0].resourceText, 'Exams');
+ assert.equal(data.results[0].resource, 'f_nested_schema');
+ assert.equal(data.results[0].text, 'Brown, John');
+ done();
+ }
+ };
+ fng.searchAll()(mockReq, mockRes);
+ });
+ });
+
+ describe('MongoDB selection', function () {
+
+ it('Should filter', function (done) {
+ var mockReq = {
+ url: '/f_nested_schema',
+ query: {
+ f: '{"exams.subject":"Physics"}'
+ },
+ params : {resourceName : 'f_nested_schema'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.length, 1);
+ done();
+ }
+ };
+ fng.collectionGet()(mockReq, mockRes);
+ });
+
+ it('Should aggregate and return appropriate records', function (done) {
+ var mockReq = {
+ url: '/api/f_nested_schema',
+ query: {
+ a: '[{"$unwind":"$exams"},{"$sort":{"exams.score":1}},{"$group":{"_id":{"id":"$_id"},"bestSubject":{"$last":"$exams.subject"}}},{"$match":{"bestSubject":"English"}},{"$project":{"_id":"$_id.id"}}]'
+ },
+ params: {resourceName: 'f_nested_schema'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.length, 2);
+ assert.notEqual(null, data.find(function(obj) {return obj.forename === 'John'}));
+ assert.notEqual(null, data.find(function(obj) {return obj.forename === 'Jenny'}));
+ done();
+ }
+ };
+ fng.collectionGet()(mockReq, mockRes);
+ });
+
+ it('Should combine aggregation and filtering', function (done) {
+ var mockReq = {
+ url: '/api/f_nested_schema',
+ query: {
+ f:'{"_id":"51c583d5b5c51226db418f15"}',
+ a: '[{"$unwind":"$exams"},{"$sort":{"exams.score":1}},' +
+ '{"$group":{"_id":{"id":"$_id"},"bestSubject":{"$last":"$exams.subject"}}},{"$match":{"bestSubject":"English"}},' +
+ '{"$project":{"_id":"$_id.id"}}]'
+ },
+ params : {resourceName: 'f_nested_schema'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.length, 1);
+ assert.equal(data[0].forename, 'John');
+ done();
+ }
+ };
+ fng.collectionGet()(mockReq, mockRes);
+ });
+ });
+
+});
diff --git a/test/api/ControlAPISpec.js b/test/api/ControlAPISpec.js
new file mode 100644
index 00000000..1329648c
--- /dev/null
+++ b/test/api/ControlAPISpec.js
@@ -0,0 +1,211 @@
+'use strict';
+
+var assert = require('assert');
+var formsAngular = require('../../dist/server/data_form.js');
+var express = require('express');
+var async = require('async');
+var path = require('path');
+var fs = require('fs');
+var _ = require('lodash');
+var exec = require('child_process').exec;
+var mongoose = require('mongoose');
+
+describe('original API', function () {
+
+ var fng, app;
+
+ before(function (done) {
+ app = express();
+
+ fng = new (formsAngular)(mongoose, app, {urlPrefix: '/api/'});
+
+ mongoose.connect('mongodb://localhost/forms-ng_test', {
+ useMongoClient: true,
+ keepAlive: 1,
+ connectTimeoutMS: 30000,
+ reconnectTries: 30,
+ reconnectInterval: 5000
+ });
+ mongoose.connection.on('error', function () {
+ console.error('connection error', arguments);
+ });
+
+ mongoose.connection.on('open', function () {
+ // Bootstrap models
+ var modelsPath = path.join(__dirname, '/models');
+ fs.readdirSync(modelsPath).forEach(function (file) {
+ var fname = modelsPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ fng.addResource(file.slice(0, -3), require(fname), {suppressDeprecatedMessage: true});
+ }
+ });
+ });
+
+ // Import test data
+ var dataPath = path.join(__dirname, 'data');
+ async.each(fs.readdirSync(dataPath), function (file, callback) {
+ var fname = dataPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ exec('mongoimport --db forms-ng_test --drop --collection ' + file.slice(0, 1) + 's --jsonArray < ' + fname, function(error, stdout, stderr) {
+ if (error !== null) {
+ callback('Error executing ' + command + ' : ' + error + ' (Code = ' + error.code + ' ' + error.signal + ') : ' + stderr + ' : ' + stdout);
+ } else {
+ callback();
+ }
+ });
+ }
+ }, function (err) {
+ if (err) {
+ console.log('Problem importing test data ' + err.message);
+ } else {
+ done();
+ }
+ });
+ });
+
+ after(function (done) {
+ mongoose.connection.db.dropDatabase(function () {
+ mongoose.disconnect(function () {
+ done();
+ });
+ });
+ });
+
+ it('returns models', function () {
+ var mockReq = null;
+ var mockRes = {
+ send: function (models) {
+ assert.equal(models.length, 11);
+ assert(_.find(models, function (resource) {
+ return resource.resourceName === 'b_using_options';
+ }).options.hide.indexOf('login') > -1, 'must send login as a hidden field');
+ }
+ };
+ fng.models()(mockReq, mockRes);
+ });
+
+ it('returns straight schema', function (done) {
+ var mockReq = {params : {resourceName: 'a_unadorned_mongoose'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 8);
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(schema[keys[1]].path, 'forename');
+ assert.equal(schema[keys[2]].path, 'phone');
+ assert.equal(schema[keys[3]].path, 'weight');
+ assert.equal(schema[keys[4]].path, 'eyeColour');
+ assert.equal(schema[keys[5]].path, 'dateOfBirth');
+ assert.equal(schema[keys[6]].path, 'accepted');
+ assert.equal(schema[keys[7]].path, '_id');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+ it('returns nested schema', function (done) {
+ var mockReq = {params : {resourceName: 'f_nested_schema'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 5);
+ assert.equal(keys[0], 'surname');
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(keys[1], 'forename');
+ assert.equal(schema[keys[1]].path, 'forename');
+ assert.equal(keys[2], 'aTest');
+ assert.equal(schema[keys[2]].path, 'aTest');
+ assert.equal(keys[3], 'exams');
+ keys = Object.keys(schema[keys[3]].schema);
+ assert.equal(keys.length, 6);
+ assert.equal(keys[0], 'subject');
+ assert.equal(schema.exams.schema[keys[0]].path, 'subject');
+ assert.equal(keys[3], 'result');
+ assert.equal(schema.exams.schema[keys[3]].path, 'result');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+
+ it('returns forms schema', function (done) {
+ var mockReq = {params : {resourceName: 'b_using_options', formName: 'justnameandpostcode'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 4);
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(schema[keys[1]].path, 'address.postcode');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+ it('supports nested schemas within form schemas', function (done) {
+ var mockReq = {params : {resourceName: 'f_nested_schema', formName: 'EnglishAndMaths'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 3);
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(keys[0], 'surname');
+ assert.equal(schema[keys[1]].path, 'forename');
+ assert.equal(keys[1], 'forename');
+ assert.equal(keys[2], 'exams');
+ keys = Object.keys(schema[keys[2]].schema);
+ assert.equal(keys.length, 6);
+ assert.equal(keys[0], 'subject');
+ assert.equal(schema.exams.schema[keys[0]].path, 'subject');
+ assert.equal(keys[3], 'result');
+ assert.equal(schema.exams.schema[keys[3]].path, 'result');
+ assert.equal(keys[4], 'grader');
+ assert.equal(schema.exams.schema[keys[4]].options.form.label, 'Marked by');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+ it('allows form schemas to override nested schemas', function (done) {
+ var mockReq = {params : {resourceName: 'f_nested_schema', formName: 'ResultsOnly'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 3);
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(keys[0], 'surname');
+ assert.equal(schema[keys[1]].path, 'forename');
+ assert.equal(keys[1], 'forename');
+ assert.equal(keys[2], 'exams');
+ keys = Object.keys(schema[keys[2]].schema);
+ assert.equal(keys.length, 2);
+ assert.equal(keys[0], 'subject');
+ assert.equal(schema.exams.schema[keys[0]].path, 'subject');
+ assert.equal(keys[1], 'result');
+ assert.equal(schema.exams.schema[keys[1]].path, 'result');
+ assert.equal(schema.exams.schema[keys[1]].options.form.label, 'Outcome');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+ it('supports enums with values and labels', function (done) {
+ var mockReq = {params : {resourceName: 'b_using_options'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(schema['education'].enumValues[1], 'univ');
+ assert.equal(schema['education'].options.enum.values[1], 'univ');
+ assert.equal(schema['education'].options.enum.labels[1], 'University');
+ assert.equal(schema['education'].validators[0].enumValues[1], 'univ');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+});
diff --git a/test/api/NewAddResourceAPISpec.js b/test/api/NewAddResourceAPISpec.js
new file mode 100644
index 00000000..f079ecef
--- /dev/null
+++ b/test/api/NewAddResourceAPISpec.js
@@ -0,0 +1,80 @@
+'use strict';
+
+var assert = require('assert');
+var formsAngular = require('../../dist/server/data_form.js');
+var express = require('express');
+var path = require('path');
+var fs = require('fs');
+var _ = require('lodash');
+var mongoose = require('mongoose');
+
+describe('mongoose collection name API', function () {
+
+ var fng, app;
+
+ before(function (done) {
+ app = express();
+
+ fng = new (formsAngular)(mongoose, app, {urlPrefix: '/api/'});
+
+ mongoose.connect('mongodb://localhost/forms-ng_test', {useMongoClient: true});
+ mongoose.connection.on('error', function () {
+ console.error('connection error', arguments);
+ });
+
+ mongoose.connection.once('open', function () {
+ // Bootstrap models
+ var modelsPath = path.join(__dirname, '/models');
+ fs.readdirSync(modelsPath).forEach(function (file) {
+ var fname = modelsPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ fng.newResource(require(fname), {suppressDeprecatedMessage: true});
+ }
+ });
+ done();
+ });
+
+ });
+
+ after(function (done) {
+ mongoose.connection.db.dropDatabase(function () {
+ mongoose.disconnect(function () {
+ done();
+ });
+ });
+ });
+
+ it('returns models', function () {
+ var mockReq = null;
+ var mockRes = {
+ send: function (models) {
+ assert.equal(models.length, 11);
+ assert(_.find(models, function (resource) {
+ return resource.resourceName === 'B';
+ }).options.hide.indexOf('login') > -1, 'must send login as a hidden field');
+ }
+ };
+ fng.models()(mockReq, mockRes);
+ });
+
+ it('returns straight schema', function (done) {
+ var mockReq = {params : {resourceName: 'A'}};
+ var mockRes = {
+ send: function (schema) {
+ var keys = Object.keys(schema);
+ assert.equal(keys.length, 8);
+ assert.equal(schema[keys[0]].path, 'surname');
+ assert.equal(schema[keys[1]].path, 'forename');
+ assert.equal(schema[keys[2]].path, 'phone');
+ assert.equal(schema[keys[3]].path, 'weight');
+ assert.equal(schema[keys[4]].path, 'eyeColour');
+ assert.equal(schema[keys[5]].path, 'dateOfBirth');
+ assert.equal(schema[keys[6]].path, 'accepted');
+ assert.equal(schema[keys[7]].path, '_id');
+ done();
+ }
+ };
+ fng.schema()(mockReq, mockRes);
+ });
+
+});
diff --git a/test/api/data-api.js b/test/api/data-api.js
deleted file mode 100644
index 79dc00cb..00000000
--- a/test/api/data-api.js
+++ /dev/null
@@ -1,375 +0,0 @@
-var exec = require('child_process').exec
- , _ = require('underscore')
- , assert = require('assert')
- , mongoose = require('mongoose')
- , c_subdoc_example = require('./../../server/models/c_subdoc_example')
- ;
-
-describe('Read Data API', function () {
-
- var aData, bData;
-
- before(function (done) {
- exec('curl 0.0.0.0:3001/api/a_unadorned_mongoose',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a failed')
- }
- aData = JSON.parse(stdout);
- exec('curl 0.0.0.0:3001/api/b_using_options',
- function (error, stdout) {
- if (error) {
- throw new Error('curl b failed')
- }
- bData = JSON.parse(stdout);
- done();
- });
- });
- });
-
- it('should send the right number of records', function () {
- assert.equal(aData.length, 2);
- });
-
- it('should send the all the fields of mongoose schema', function () {
- assert(aData[0].surname, 'must send surname');
- assert(aData[0].forename, 'must send forename');
- assert(aData[0].weight, 'must send weight');
- assert(aData[0].eyeColour, 'must send eyeColour');
- assert(aData[0].dateOfBirth, 'must send dob');
- assert.equal(aData[0].accepted, false, 'must send accepted');
- });
-
- it('should filter out records that do not match the find func', function () {
- assert.equal(bData.length, 2);
- });
-
- it('should not send secure fields of a modified schema', function () {
- assert(bData[0].surname, "Must send surname");
- assert(bData[0].forename, "Must send forename");
- assert.equal(Object.keys(bData[0]).indexOf('login'), -1, 'Must not send secure login field');
- assert.equal(Object.keys(bData[0]).indexOf('passwordHash'), -1, 'Must not send secure password hash field');
- assert(bData[0].email, "Must send email");
- assert(bData[0].weight, "Must send weight");
- assert(bData[0].accepted, "Must send accepted");
- assert(bData[0].interviewScore, 'Must send interview score');
- assert(bData[0].freeText, 'Must send freetext');
- });
-
- it('should not send secure fields of a modified subschema', function () {
- assert(bData[0].address.line1, "Must send line1");
- assert(bData[0].address.town, "Must send town");
- assert(bData[0].address.postcode, "Must send postcode");
- assert.equal(Object.keys(bData[0]).indexOf('address.surveillance'), -1, 'Must not send secure surveillance field');
- })
-});
-
-describe('Update Data API', function () {
-
- it('should create/update/delete a record calling onCleanseRequestSync()', function (done) {
- // create
- exec('curl -X POST -H "Content-Type: application/json" -d \'{"surname":"TestCreate","accepted":false}\' http://0.0.0.0:3001/api/b_using_options',
- function (error, stdout) {
- if (error) {
- throw new Error('curl b failed')
- }
- var bData = JSON.parse(stdout);
- assert.equal(bData.surname, "TestCreate");
- assert.equal(bData.ipAddress, "127.0.0.1"); // onCleanseRequestSync
- var id = bData._id;
- // update
- exec('curl -X POST -H "Content-Type: application/json" -d \'{"forename":"Alfie"}\' http://0.0.0.0:3001/api/b_using_options/' + id,
- function (error, stdout) {
- if (error) {
- throw new Error('curl b2 failed')
- }
- bData = JSON.parse(stdout);
- assert.equal(bData.forename, "Alfie");
- // delete
- exec('curl -X DELETE http://0.0.0.0:3001/api/b_using_options/' + id,
- function (error, stdout) {
- if (error) {
- throw new Error('curl b3 failed')
- }
- bData = JSON.parse(stdout);
- assert(bData.success);
- done();
- }
- );
- }
- );
- }
- );
- });
-
- it.skip("should update a date field, and support date fields in ?f= and ?a= queries",function(done){
- exec('curl 0.0.0.0:3001/api/a_unadorned_mongoose/519a6075b320153869b17599',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a(date) failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.surname,'TestPerson1');
- aData.dateOfBirth = new Date(1998,10,4);
- exec('curl -X POST -H "Content-Type: application/json" -d \'' + JSON.stringify(aData) + '\' http://0.0.0.0:3001/api/a_unadorned_mongoose/519a6075b320153869b17599',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a2(date) failed')
- }
- aData = JSON.parse(stdout);
- assert.equal(aData.dateOfBirth, "1998-11-04T00:00:00.000Z");
- // 0.0.0.0:3001/#/a_unadorned_mongoose?f={"dateOfBirth":"1998-11-04"}
- exec('curl 0.0.0.0:3001/api/a_unadorned_mongoose?f=%7B%22dateOfBirth%22%3A%221998-11-04%22%7D',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a3(date) failed')
- }
- aData = JSON.parse(stdout);
- assert.equal(aData.length,1);
- assert.equal(aData[0].surname,'TestPerson1');
-// http://0.0.0.0:3001/#/a_unadorned_mongoose?a=[{"$match":{22dateOfBirth%22%3A%221998-11-04%22%}},{"$project":{"surname":1}}]
- exec('curl 0.0.0.0:3001/api/a_unadorned_mongoose?a=%5B%7B 7D%5D',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a4(date) failed')
- }
- aData = JSON.parse(stdout);
- assert.equal(aData.length,1);
- assert.equal(aData[0].surname,'TestPerson1');
- done();
- }
- );
- }
- );
- }
- );
- }
- );
- })
-});
-
-describe('Search API', function() {
-
- it('should find a single match', function(done) {
- exec('curl 0.0.0.0:3001/api/search?q=IsA',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,1);
- done();
- });
- });
-
- it('should find two matches', function(done) {
- exec('curl 0.0.0.0:3001/api/search?q=Test',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,2);
- done();
- });
- });
-
- it('should not find records that do not meet find function', function (done) {
- exec('curl 0.0.0.0:3001/api/search?q=Not',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,0);
- done();
- });
- });
-
- it('should not find records indexed on a no-search field', function (done) {
- exec('curl 0.0.0.0:3001/api/search?q=ReportingIndex',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,0);
- done();
- });
- });
-
- it('should support searchOrder option', function(done) {
- exec('curl 0.0.0.0:3001/api/search?q=Smi',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,10);
- assert.equal(aData.results[0].text, 'Smith00 John00');
- assert.equal(aData.results[9].text, 'Smith10 John10');
- assert.equal(JSON.stringify(aData.results).indexOf('John07'),-1);
- done();
- });
- });
-
- it('should find a record from a partial initial string', function(done){
- exec('curl 0.0.0.0:3001/api/search?q=ann',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,1);
- assert.equal(aData.results[0].id, "51c583d5b5c51226db418f16");
- assert.equal(aData.results[0].resource, 'f_nested_schema');
- assert.equal(aData.results[0].resourceText, 'Exams');
- assert.equal(aData.results[0].text, 'Smith, Anne');
- done();
- });
- });
-
- it('should find a record from multiple partial initial strings', function(done){
- exec('curl 0.0.0.0:3001/api/search?q=smi%20john04',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.notEqual(aData.moreCount,0);
- assert.equal(aData.results[0].text, 'Smith04 John04'); // Double hit
- assert.equal(aData.results[1].text, 'Smith00 John00'); // normal weighting
- done();
- });
- });
-
-
- it('should support searchResultFormat option', function() {
- exec('curl 0.0.0.0:3001/api/search?q=Br',
- function (error, stdout) {
- if (error) {
- throw new Error('curl failed')
- }
- var aData = JSON.parse(stdout);
- assert.equal(aData.results.length,2);
- assert.equal(aData.results[0].resourceText,'Exams');
- assert.equal(aData.results[0].resource,'f_nested_schema');
- assert.equal(aData.results[0].text, 'Brown, John');
- });
- });
-
-});
-
-describe('Models API', function () {
-
- var aData;
-
- before(function (done) {
- exec('curl 0.0.0.0:3001/api/models',
- function (error, stdout) {
- if (error) {
- throw new Error('curl a failed')
- }
- aData = JSON.parse(stdout);
- done();
- });
- });
-
- it('should send at least two records', function () {
- assert(aData.length >= 2);
- });
-
- it('should send login as a hidden field in b_using_options', function () {
- assert(_.find(aData,function (resource) {
- return resource.resource_name === "b_using_options";
- }).options.hide.indexOf('login') > -1, 'must send login as a hidden field');
- });
-});
-
-describe('MongoDB selection API', function () {
-
- it('Should filter', function (done) {
- exec('curl 0.0.0.0:3001/api/f_nested_schema?f=%7B%22exams.subject%22:%22Physics%22%7D', function (err, stdout) {
- if (err) {
- throw new Error('curl f with filter failed')
- }
- var data = JSON.parse(stdout);
- assert.equal(data.length, 1);
- done();
- })
- });
-
- it('Should aggregate and return appropriate records', function (done) {
- exec('curl 0.0.0.0:3001/api/f_nested_schema?a=%5B%7B%22%24unwind%22%3A%22%24exams%22%7D%2C%7B%22%24sort%22%3A%7B%22exams.score%22%3A1%7D%7D%2C%7B%22%24group%22%3A%7B%22_id%22%3A%7B%22id%22%3A%22%24_id%22%7D%2C%22bestSubject%22%3A%7B%22%24last%22%3A%22%24exams.subject%22%7D%7D%7D%2C%7B%22%24match%22%3A%7B%22bestSubject%22%3A%22English%22%7D%7D%2C%7B%22%24project%22%3A%7B%22_id%22%3A%22%24_id.id%22%7D%7D%5D', function (err, stdout) {
- if (err) {
- throw new Error('curl f with aggregation failed')
- }
- var data = JSON.parse(stdout);
- assert.equal(data.length, 2);
- assert.equal(data[0].forename, 'John');
- assert.equal(data[1].forename, 'Jenny');
- done();
- })
- });
-
- it("Should combine aggregation and filtering", function (done) {
- exec('curl 0.0.0.0:3001/api/f_nested_schema?f=%7B%22_id%22:%2251c583d5b5c51226db418f15%22%7D&a=%5B%7B%22%24unwind%22%3A%22%24exams%22%7D%2C%7B%22%24sort%22%3A%7B%22exams.score%22%3A1%7D%7D%2C%7B%22%24group%22%3A%7B%22_id%22%3A%7B%22id%22%3A%22%24_id%22%7D%2C%22bestSubject%22%3A%7B%22%24last%22%3A%22%24exams.subject%22%7D%7D%7D%2C%7B%22%24match%22%3A%7B%22bestSubject%22%3A%22English%22%7D%7D%2C%7B%22%24project%22%3A%7B%22_id%22%3A%22%24_id.id%22%7D%7D%5D', function (err, stdout) {
- if (err) {
- throw new Error('curl f with aggregation and filter failed')
- }
- var data = JSON.parse(stdout);
- assert.equal(data.length, 1);
- assert.equal(data[0].forename, 'John');
- done();
- })
-
- })
-
-});
-
-describe('Secure fields', function () {
-
- before(function(done) {
- mongoose.connect('mongodb://localhost/forms-ng_test');
- done();
- });
-
- after(function () {
- mongoose.connection.close();
- });
-
- it('should not be transmitted', function (done) {
- exec('curl 0.0.0.0:3001/api/c_subdoc_example', function (err, stdout) {
- if (err) {
- throw new Error('curl c_subdoc_example failed')
- }
- var data = JSON.parse(stdout);
- assert.equal(data.length, 2);
- assert.equal(data[0].surname, 'Anderson');
- assert.equal(data[0].passwordHash, undefined);
- assert.notEqual(data[0].interview.score, undefined);
- assert.equal(data[0].interview.interviewHash, undefined);
- done();
- });
- });
-
- it('should not be overwritten', function (done) {
- exec('curl -X POST -H "Content-Type: application/json" -d \'{"surname" : "Anderson", "forename" : "John", "weight" : 124, "hairColour" : "Brown", "accepted" : true, "interview" : { "score" : 97, "date" : "23 Mar 2013" } }\' http://0.0.0.0:3001/api/c_subdoc_example/519aaaaab320153869b175e0', function (err, stdout) {
- if (err) {
- throw new Error('curl c_subdoc_example write failed')
- }
- var data = JSON.parse(stdout);
- assert.equal(data.weight,124);
- c_subdoc_example.findById("519aaaaab320153869b175e0",function(err,realRecord){
- assert.equal(realRecord.weight,124);
- assert.equal(realRecord.passwordHash,'top secret');
- assert.equal(realRecord.interview.score, 97);
- assert.equal(realRecord.interview.interviewHash, "you think I would tell you?");
- done();
- });
- });
- });
-
-});
-
-// http://0.0.0.0:3001/api/a_unadorned_mongoose?a=%5B%7B%22%24match%22:%7B%22dateOfBirth%22:%221998-11-04%22%7D%7D,%7B%22$project%22:%7B%22surname%22:1%7D%7D%5D
\ No newline at end of file
diff --git a/test/e2edata/a_unadorned_mongoose.js b/test/api/data/a_unadorned_mongoose.js
similarity index 100%
rename from test/e2edata/a_unadorned_mongoose.js
rename to test/api/data/a_unadorned_mongoose.js
diff --git a/test/api/data/b_using_options.js b/test/api/data/b_using_options.js
new file mode 100644
index 00000000..ee28546a
--- /dev/null
+++ b/test/api/data/b_using_options.js
@@ -0,0 +1,58 @@
+[
+ {
+ _id: ObjectId("519a6075b320153869b175e0"),
+ surname: "IsAccepted1",
+ forename: "John",
+ address: {
+ line1: "4 High Street",
+ town: "Anytown",
+ postcode: "AB2 3ES"},
+ email: "someone@somewhere.com",
+ weight: 124,
+ accepted: true,
+ dateOfBirth: "04 Nov 1998",
+ eyeColour: "Green",
+ hairColour: "Black",
+ login: "JohnN",
+ passwordHash: "sha1$22b5fc3b$1$60a48af349b5a95cc0ab3f29b4c95a819d944e75",
+ interviewScore: 89,
+ freeText: "Here is some tex blah blah"
+ },
+ {
+ _id: ObjectId("519a6075b320153869b155e0"),
+ surname: "IsAccepted2",
+ forename: "Johan",
+ address: {
+ line1: "4 High Street",
+ town: "Anytown",
+ postcode: "AB2 3ES"},
+ email: "ReportingIndex@somewhere.com",
+ weight: 124,
+ dateOfBirth: "04 Dec 1978",
+ eyeColour: "Brown",
+ login: "JohnI",
+ passwordHash: "sha1$22b5fc3b$1$60a33af349b5a95cc0ab3f29b4c95a819d944e75",
+ accepted: true,
+ interviewScore: 89,
+ freeText: "Here is some tex blah blah"
+ },
+ {
+ _id: ObjectId("519a6075b440153869b155e0"),
+ surname: "Jones-NotAccepted",
+ forename: "Alan",
+ address: {
+ line1: "14 High Street",
+ town: "Anothertown",
+ postcode: "AB4 3ES"},
+ email: "ReportingIndex@somewhere.com",
+ weight: 145,
+ dateOfBirth: "04 Dec 1968",
+ eyeColour: "Brown",
+ login: "AlanJ",
+ passwordHash: "sha1$22b5fc3b$1$60a33af349b5a95cc0ab3f29b4c95a819d944e75",
+ accepted: false,
+ freeText: "Here is some tex blah blah",
+ interviewScore: 93
+ }
+
+]
diff --git a/test/e2edata/c_subdoc_example.js b/test/api/data/c_subdoc_example.js
similarity index 100%
rename from test/e2edata/c_subdoc_example.js
rename to test/api/data/c_subdoc_example.js
diff --git a/test/e2edata/d_array_example.js b/test/api/data/d_array_example.js
similarity index 100%
rename from test/e2edata/d_array_example.js
rename to test/api/data/d_array_example.js
diff --git a/test/e2edata/e_referencing_another_collection.js b/test/api/data/e_referencing_another_collection.js
similarity index 100%
rename from test/e2edata/e_referencing_another_collection.js
rename to test/api/data/e_referencing_another_collection.js
diff --git a/test/e2edata/f_nested_schema.js b/test/api/data/f_nested_schema.js
similarity index 100%
rename from test/e2edata/f_nested_schema.js
rename to test/api/data/f_nested_schema.js
diff --git a/test/e2edata/g_conditional_fields.js b/test/api/data/g_conditional_fields.js
similarity index 98%
rename from test/e2edata/g_conditional_fields.js
rename to test/api/data/g_conditional_fields.js
index 3143c860..439d9ee9 100644
--- a/test/e2edata/g_conditional_fields.js
+++ b/test/api/data/g_conditional_fields.js
@@ -24,7 +24,7 @@
_id : ObjectId("51c583d5b9991226db418f03"),
surname: "Smith03",
sex: 'M',
- bribeAmount: 123,
+ bribeAmount: 12345,
forename: "John03"
},
{
diff --git a/test/e2edata/h_deep_nesting.js b/test/api/data/h_deep_nesting.js
similarity index 100%
rename from test/e2edata/h_deep_nesting.js
rename to test/api/data/h_deep_nesting.js
diff --git a/test/e2edata/j_directive_with_form.js b/test/api/data/j_directive_with_form.js
similarity index 100%
rename from test/e2edata/j_directive_with_form.js
rename to test/api/data/j_directive_with_form.js
diff --git a/test/api/listAPISpec.js b/test/api/listAPISpec.js
new file mode 100644
index 00000000..811a56ea
--- /dev/null
+++ b/test/api/listAPISpec.js
@@ -0,0 +1,112 @@
+'use strict';
+
+var assert = require('assert');
+var formsAngular = require('../../dist/server/data_form.js');
+var express = require('express');
+var async = require('async');
+var path = require('path');
+var fs = require('fs');
+var exec = require('child_process').exec;
+var mongoose = require('mongoose');
+
+describe('List API', function () {
+
+ var fng, app;
+
+ before(function (done) {
+
+ app = express();
+
+ fng = new (formsAngular)(mongoose, app, {urlPrefix: '/api/'});
+
+ mongoose.connect('mongodb://localhost/forms-ng_test', {useMongoClient: true});
+ mongoose.connection.on('error', function () {
+ console.error('connection error', arguments);
+ });
+
+ mongoose.connection.on('open', function () {
+ // Bootstrap models
+ var modelsPath = path.join(__dirname, '/models');
+ fs.readdirSync(modelsPath).forEach(function (file) {
+ var fname = modelsPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ fng.addResource(file.slice(0, -3), require(fname), {suppressDeprecatedMessage: true});
+ }
+ });
+ });
+
+ // Import test data
+ var dataPath = path.join(__dirname, 'data');
+ async.each(fs.readdirSync(dataPath), function (file, callback) {
+ var fname = dataPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ exec('mongoimport --db forms-ng_test --drop --collection ' + file.slice(0, 1) + 's --jsonArray < ' + fname, callback);
+ }
+ }, function (err) {
+ if (err) {
+ console.log('Problem importing test data ' + err.message);
+ } else {
+ done();
+ }
+ });
+ });
+
+ after(function (done) {
+ mongoose.connection.db.dropDatabase(function () {
+ mongoose.disconnect(function () {
+ done();
+ });
+ });
+ });
+
+ it('returns explicit list fields', function (done) {
+ var mockReq = {
+ url: '/api/c_subdoc_example/519aaaaab320153869b175e0/list',
+ params: {resourceName: 'c_subdoc_example', id: '519aaaaab320153869b175e0'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.list, 'Anderson John');
+ done();
+ }
+ };
+ fng.entityList()(mockReq, mockRes);
+ });
+
+ it('returns hidden list fields', function (done) {
+ var mockReq = {
+ url: '/api/b_using_options/519a6075b320153869b175e0/list',
+ params: {resourceName: 'b_using_options', id: '519a6075b320153869b175e0'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.list, 'IsAccepted1 John true 89');
+ done();
+ }
+ };
+ fng.entityList()(mockReq, mockRes);
+ });
+
+ it('returns first string field if no explicit list fields', function (done) {
+ var mockReq = {
+ url: '/api/a_unadorned_mongoose/519a6075b320153869b17599/list',
+ params: {resourceName: 'a_unadorned_mongoose', id: '519a6075b320153869b17599'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.list, 'TestPerson1');
+ done();
+ }
+ };
+ fng.entityList()(mockReq, mockRes);
+ });
+
+ it('returns looked up fields', function() {
+
+ });
+
+ it('handles list items in search', function() {
+
+ });
+
+});
diff --git a/test/api/models/a_unadorned_mongoose.js b/test/api/models/a_unadorned_mongoose.js
new file mode 100644
index 00000000..f23a63da
--- /dev/null
+++ b/test/api/models/a_unadorned_mongoose.js
@@ -0,0 +1,24 @@
+'use strict';
+
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var ASchema = new Schema({
+ surname: {type: String, required: true, index: true},
+ forename: {type: String, index: true},
+ phone: {type: String},
+ weight: Number,
+ eyeColour: {type: String, required: true, enum: ['Blue', 'Brown', 'Green', 'Hazel']},
+ dateOfBirth: Date,
+ accepted: Boolean
+});
+
+var A;
+
+try {
+ A = mongoose.model('A');
+} catch (e) {
+ A = mongoose.model('A', ASchema);
+}
+
+module.exports = A;
diff --git a/test/api/models/b_using_options.js b/test/api/models/b_using_options.js
new file mode 100644
index 00000000..c05360dc
--- /dev/null
+++ b/test/api/models/b_using_options.js
@@ -0,0 +1,151 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var BSchema = new Schema({
+ surname: {type: String, required: true, index: true, list: {}}, // this field appears in a listing and the default edit form header
+ forename: {type: String, list: true, index: true}, // this field appears in a listing and the default edit form header
+ website: {type: String, form: {type: 'url'}},
+ login: {type: String, secure: true, form: {hidden: true}}, // secure prevents the data from being sent by the API, hidden from being shown on the default form
+ passwordHash: {type: String, secure: true, form: {hidden: true}},
+ address: {
+ line1: {type: String, form: {label: 'Address'}}, // this label overrides the one generated from the field name
+ line2: {type: String, form: {label: null}}, // null label - gives a blank label
+ line3: {type: String, form: {label: null, add: 'random attributes', class : 'some classes here'}},
+ town: {type: String, form: {label: 'Town', placeHolder: 'Post town'}}, // You can specify place holders
+ postcode: {type: String,
+ match: /^(GIR 0AA|[A-Z]{1,2}[0-9][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2})$/,
+ form: {label: 'Postcode', size: 'small', help: 'Enter your UK postcode (for example TN2 1AA)'}}, // help displays on the line under the control, size adds matching bootstrap input- class
+ country: {type: String, form: {label: 'Country', hidden: true}},
+ surveillance: {type: Boolean, secure: true, form: {hidden: true}}
+ },
+
+ // The email field is indexed, but the noSearch property means the index is not used in the searchBox searches
+ // A use case for this would be an index that is used in reports for grouping which has no meaning in a search.
+ //
+ // The field has a custom directive to prepend (which is defined in /app/demo/directives/bespoke-field.js)
+ email: {type: String, index: true, noSearch: true, form: {directive: 'email-field'}},
+ weight: {type: Number, min: 5, max: 300, form: {label: 'Approx Weight (lbs)', // this label overrides the one generated from the field name
+ step: 5}}, // input uses the min and max from the Mongoose schema, and the step from the form object
+
+ hairColour: {
+ type: String,
+ enum: ['Black', 'Blond', 'Brown', 'Fair', 'Grey', 'What hair?'],
+ required: false,
+ form: {
+ directive: 'fng-ui-select',
+ placeHolder: 'Choose hair colour...',
+ help:'This controller uses the fng-ui-select plugin which pulls in the angular-ui ui-select component .'
+ }
+ },
+ eyeColour: {
+ type: String,
+ enum: ['Blue', 'Brown', 'Green', 'Hazel'],
+ required: false,
+ form: {
+ placeHolder: 'Select eye colour', // Placeholders work in a combo box
+ select2: {}, // deprecated - use fng-ui-select
+ help: 'This control has had an event handler added to it (which looks horrid - sorry!).' +
+ ' See post form-input generation processing section of documentation for details. This field uses the (deprecated) ui-select2 component.'
+ }
+ },
+ sex: {type: String, enum: ['Male', 'Female'], form: {type: 'radio', inlineRadio: true}},
+ dateOfBirth: {type: Date, form: {helpInline: 'When is their birthday?'}},
+ education: {type: String, enum: {values:['sec', 'univ', 'mas', 'dr'], labels:['Secondary', 'University', 'Masters', 'Doctorate']}, form: {type: 'radio'}},
+ accepted: {type: Boolean, required: true, form: {helpInline: 'Did we take them?'}, list: {}}, // helpInline displays to the right of the input control
+ interviewScore: {type: Number, form: {hidden: true}, list: {}}, // this field does appear on listings, even though it is hidden on default form
+ freeText: {
+ type: String,
+ form: {
+ type: 'textarea',
+ rows: 5,
+ help: 'There is some validation on this field to ensure that the word "rude" is not entered. Try it to see the record level error handling.'
+ }
+ },
+ resizingText: {type: String, form: {type: 'textarea', rows: 'auto', help: 'This field resizes thanks to the angular-elastic module'}},
+ formattedText: {
+ type: String,
+ form: {
+ type: 'textarea',
+ editor: 'ckEditor',
+ help: 'This field uses CKEditor and the ng-ckeditor module'
+ }
+ },
+ ipAddress: {type: String, form: {hidden: true}},
+ //any field containing password will display as a password field (dots).
+ // This can be overidden by adding 'form:{password:false}' - also this can be true if the field is NOT called password
+ password: {type: String}
+});
+
+BSchema.pre('save', function (next) {
+ // Check for rude words (well, the word "rude", actually) to show an error
+
+ if (this.freeText && this.freeText.indexOf('rude') !== -1) {
+ return next(new Error('Wash your mouth! You must not use rude words.'));
+ }
+ return next();
+});
+
+var B;
+try {
+ B = mongoose.model('B');
+} catch (e) {
+ B = mongoose.model('B', BSchema);
+}
+
+// Alternative form schemas can be defined as shown below
+BSchema.statics.form = function (layout) {
+ var formSchema = '';
+ switch (layout) {
+ case 'justnameandpostcode' :
+ // the object overrides the form object in the schema
+ formSchema = {
+ surname: {label: 'Family Name'},
+ 'address.postcode': {},
+ accepted: {},
+ 'address.country': {hidden: false}
+ };
+ break;
+ case 'ipAddress' : // used in testing
+ formSchema = {
+ ipAddress: {hidden: false}
+ };
+ break;
+
+ }
+ return formSchema;
+};
+
+BSchema.statics.findAccepted = function (req, cb) {
+ // Only show the accepted items
+ cb(null, {accepted: true});
+};
+
+BSchema.statics.prepareSave = function (doc, req, cb) {
+ doc.ipAddress = req.ip;
+ cb(null);
+};
+
+BSchema.statics.report = function (report) {
+ var reportSchema = '';
+ switch (report) {
+ case 'allVisible' :
+ reportSchema = {
+ pipeline: [
+ {$group: {_id: '$accepted', count: {'$sum': 1}}}
+ ],
+ title: 'Numbers of Applicants By Status'
+ };
+ break;
+ }
+ return reportSchema;
+};
+
+
+module.exports = {
+ model: B, // pass the model in an object if you want to add options
+ findFunc: BSchema.statics.findAccepted, // this can be used to 'pre' filter selections.
+ // A common use case is to restrict a user to only see their own records
+ // as described in https://groups.google.com/forum/?fromgroups=#!topic/mongoose-orm/TiR5OXR9mAM
+ onSave: BSchema.statics.prepareSave // a hook that can be used to add something from environment to record before update
+};
diff --git a/test/api/models/c_subdoc_example.js b/test/api/models/c_subdoc_example.js
new file mode 100644
index 00000000..4a36a272
--- /dev/null
+++ b/test/api/models/c_subdoc_example.js
@@ -0,0 +1,27 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var CSchema = new Schema({
+ surname: {type: String, list: {}, index: true},
+ forename: {type: String, list: true},
+ weight: {type: Number, form: {label: 'Weight (lbs)'}},
+ hairColour: {type: String, enum: ['Black', 'Brown', 'Blonde', 'Bald'], required: true, form: {placeHolder: 'Select hair colour (required)', select2: {}}}, // Required combo has appropriate styling
+ dateOfBirth: Date,
+ accepted: Boolean,
+ passwordHash: {type: String, secure: true, forms: {hidden: true}},
+ interview: {
+ score: {type: Number},
+ date: {type: Date},
+ interviewHash: {type: String, secure: true, forms: {hidden: true}}
+ }
+});
+
+var C;
+try {
+ C = mongoose.model('C');
+} catch (e) {
+ C = mongoose.model('C', CSchema);
+}
+
+module.exports = C;
diff --git a/test/api/models/d_array_example.js b/test/api/models/d_array_example.js
new file mode 100644
index 00000000..18f4dcad
--- /dev/null
+++ b/test/api/models/d_array_example.js
@@ -0,0 +1,22 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var DSchema = new Schema({
+ surname: {type: String, list: {}, index: true},
+ forename: {type: String, list: true},
+ weight: {type: Number, form: {label: 'Weight (lbs)'}},
+ dateOfBirth: Date,
+ accepted: Boolean,
+ specialSubjects: [String]
+});
+
+var D;
+try {
+ D = mongoose.model('D');
+} catch (e) {
+ D = mongoose.model('D', DSchema);
+}
+
+module.exports = D;
+
diff --git a/test/api/models/e_referencing_another_collection.js b/test/api/models/e_referencing_another_collection.js
new file mode 100644
index 00000000..7cd39326
--- /dev/null
+++ b/test/api/models/e_referencing_another_collection.js
@@ -0,0 +1,52 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var ESchema = new Schema({
+ surname: {type: String, list: {}, index: true},
+ forename: {type: String, list: true},
+ weight: {type: Number, form: {label: 'Weight (lbs)'}},
+ mentor: { type: Schema.Types.ObjectId, ref: 'c_subdoc_example'},
+ teacher: { type: Schema.Types.ObjectId, ref: 'b_using_options', form: {select2: {fngAjax: true}}},
+ dateOfBirth: Date,
+ assistants: [
+ { type: Schema.Types.ObjectId, ref: 'a_unadorned_mongoose'}
+ ],
+ team: [
+ { type: Schema.Types.ObjectId, ref: 'd_array_example', form: {select2: true}}
+ ],
+ accepted: Boolean
+});
+
+var E;
+try {
+ E = mongoose.model('E');
+} catch (e) {
+ E = mongoose.model('E', ESchema);
+}
+
+ESchema.statics.report = function (report) {
+ var reportSchema = '';
+ switch (report) {
+ case 'class-sizes' :
+ reportSchema = {
+ pipeline: [
+ {$group: {_id: '$teacher', count: {'$sum': 1}}}
+ ],
+ title: 'Class Sizes',
+ columnDefs: [
+ {field: '_id', displayName: 'Teacher'},
+ {field: 'count', displayName: 'Number in Class'}
+ ],
+ columnTranslations: [
+ {field: '_id', ref: 'b_using_options'}
+ ]
+ };
+ break;
+ }
+ return reportSchema;
+};
+
+module.exports = E;
+
+
diff --git a/test/api/models/f_nested_schema.js b/test/api/models/f_nested_schema.js
new file mode 100644
index 00000000..f4a7df94
--- /dev/null
+++ b/test/api/models/f_nested_schema.js
@@ -0,0 +1,90 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var ExamsSchema = new Schema({
+ subject: String,
+ examDate: Date,
+ score: Number,
+ result: {type: String, enum: ['distinction', 'merit', 'pass', 'fail']},
+ grader: { type: Schema.Types.ObjectId, ref: 'b_using_options', form: {select2: {fngAjax: true}, label:'Marked by'}},
+ retakeDate: {type: Date, form: {showWhen: {lhs: '$exams.result', comp: 'eq', rhs: 'fail'}}}
+}, {_id: false});
+
+var FSchema = new Schema({
+ surname: {type: String, index: true, list: {}},
+ forename: {type: String, index: true, list: true},
+ aTest: { type: Schema.Types.ObjectId, ref: 'b_using_options'},
+
+// exams: [ExamsSchema] // defaults to horizontal compact form
+ // or
+ exams: {type: [ExamsSchema], form: {formStyle: 'inline'}}
+});
+
+var F;
+try {
+ F = mongoose.model('F');
+} catch (e) {
+ F = mongoose.model('F', FSchema);
+}
+
+F.prototype.searchResultFormat = function () {
+
+ // You can set up a function to modify search result display and the
+ // ordering within a collection
+ var weighting;
+
+ weighting = this.forename === 'John' ? 2 : 3;
+
+ return {
+ resource: 'f_nested_schema',
+ resourceText: 'Exams',
+ id: this._id,
+ weighting: weighting,
+ text: this.surname + ', ' + this.forename
+ };
+};
+
+FSchema.statics.form = function (layout) {
+ var formSchema = '';
+ switch (layout) {
+ case 'English' :
+ // Just the English exam from the array
+ formSchema = {
+ surname: {},
+ forename: {},
+ exams: {subkey: {keyList: {subject: 'English'}, containerType: 'well', title: 'English Exam'}}
+ };
+ break;
+ case 'EnglishAndMaths' :
+ // English and Maths exams from the array
+ formSchema = {
+ surname: {},
+ forename: {},
+ exams: {subkey: [
+ {keyList: {subject: 'English'}, containerType: 'well', title: 'English Exam'},
+ {keyList: {subject: 'Maths'}, containerType: 'well', title: 'Maths Exam'}
+ ]}
+ };
+ break;
+ case 'ResultsOnly' :
+ // Demonstration of specifying fields within sub schemas in a form schema
+ formSchema = {
+ surname: {},
+ forename: {},
+ exams: {schema: {
+ subject: {},
+ result: {label: 'Outcome'}
+ }}
+ };
+ break;
+ }
+ return formSchema;
+};
+
+module.exports = {
+ model: F,
+ searchResultFormat: F.prototype.searchResultFormat
+};
+
+
diff --git a/test/api/models/g_conditional_fields.js b/test/api/models/g_conditional_fields.js
new file mode 100644
index 00000000..430fde33
--- /dev/null
+++ b/test/api/models/g_conditional_fields.js
@@ -0,0 +1,112 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var GSchema = new Schema({
+ surname: {type: String, list: {}, index: true},
+ forename: {type: String, list: true, index: true},
+ sex: {type: String, enum: ['F', 'M']},
+ accepted: {type: Boolean, form: {help: 'When someone is accepted additional fields appear'}},
+ startDate: {type: Date, form: {showWhen: {lhs: '$accepted', comp: 'eq', rhs: true}}},
+ startingPosition: {type: String, form: {showWhen: {lhs: '$accepted', comp: 'eq', rhs: true}}},
+ bribeAmount: {type: Number, form: {help: 'Try a number between 10 and 200 to see an angular expression used in a conditional'}},
+ loggedInBribeBook: {type: Boolean, form: {showWhen: 'record.bribeAmount >= 10 && record.bribeAmount <= 200'}}
+});
+
+var G;
+try {
+ G = mongoose.model('G');
+} catch (e) {
+ G = mongoose.model('G', GSchema);
+}
+
+GSchema.statics.report = function (report) {
+ var reportSchema = '',
+ fullDescription = {field: '_id', translations: [ {value: 'M', display: 'Male'}, {value: 'F', display: 'Female'}, {'value': '', 'display': 'Unspecified'}]};
+ switch (report) {
+ case 'breakdownbysex' :
+ reportSchema = {
+ pipeline: [
+ {$group: {_id: '$sex', count: {'$sum': 1}}},
+ {$sort: {_id: 1}}
+ ],
+ title: 'Numbers of Applicants By Sex',
+ columnDefs: [
+ {field: '_id', displayName: 'Sex', totalsRow: 'Total', 'width': '160px'},
+ {field: 'count', displayName: 'No of Applicants', totalsRow: '$SUM', 'width': '160px', 'cellFilter': 'number', 'align': 'right'}
+ ],
+ columnTranslations: [fullDescription]
+ };
+ break;
+ case 'totalforonesex' :
+ reportSchema = {
+ 'pipeline': [
+ {'$match': {'sex': '(sex)'}},
+ {'$group': {'_id': '$sex', 'count': {'$sum': 1}}}
+ ],
+ 'title': 'Numbers of Applicants By Sex',
+ 'columnDefs': [
+ {'field': '_id', 'displayName': 'Sex', 'width': '200'},
+ {'field': 'count', 'displayName': 'No of Applicants', 'align': 'right', 'width': '200'}
+ ],
+ 'columnTranslations': [fullDescription],
+ 'params': {'sex': {value: 'M', type: 'select', enum: ['Male', 'Female'], required: true, conversionExpression: 'param[0]'}}
+ };
+ break;
+ case 'totals' :
+ reportSchema = {
+ 'pipeline': [
+ {'$project': {'surname': 1, 'forename': 1, 'bribeAmount': 1, '_id': 1}}
+ ],
+ 'title': 'A report with totals and drilldown',
+ drilldown: 'g_conditional_fields/|_id|/edit',
+ 'columnDefs': [
+ {'field': 'surname', 'displayName': 'Surname', 'width': '200', totalsRow: 'Total'},
+ {'field': 'forename', 'displayName': 'Forename', 'width': 200},
+ {'field': 'bribeAmount', 'displayName': 'Bribe', 'align': 'right', 'width': '200', totalsRow: '$SUM', 'cellFilter': 'currency'}
+ ]
+ };
+ break;
+ case 'functiondemo' :
+ reportSchema = {
+ 'pipeline': [
+ {'$group': {'_id': '$sex', 'count': {'$sum': 1}, 'functionResult': {'$sum': 1}}},
+ {'$sort': {'_id':1}}
+ ],
+ 'title': 'Numbers of Applicants By Sex',
+ 'columnDefs': [
+ {'field': '_id', 'displayName': 'Sex', 'width': '200'},
+ {'field': 'count', 'displayName': 'No of Applicants', 'align': 'right', 'width': '200'},
+ {'field': 'functionResult', 'displayName': 'Applicants + 10', 'align': 'right', 'width': '200'}
+ ],
+ 'columnTranslations': [fullDescription,
+ {field: 'functionResult',
+ fn: function (row, cb) {
+ row.functionResult = row.functionResult + 10;
+ cb();
+ }}
+ ]
+ };
+ break;
+ case 'selectbynumber' :
+ reportSchema = {
+ 'pipeline': [
+ {'$group': {'_id': '$sex', 'count': {'$sum': 1}}},
+ {'$match': {'count': '(number_param)'}}
+ ],
+ 'params': {'number_param': {value: 11, type: 'number', required: true}}
+ };
+ break;
+ }
+ return reportSchema;
+};
+
+module.exports = {
+ model: G,
+ searchImportance: 1,
+ searchOrder: {surname: 1},
+ listOrder: {surname: 1}
+};
+
+
+// "pipeline":[{"$group":{"_id":"$sex","count":{"$sum":1}}},{"$match":{"count":"(number_param)"}}],"params":{"number_param":11}
diff --git a/test/api/models/h_deep_nesting.js b/test/api/models/h_deep_nesting.js
new file mode 100644
index 00000000..91ce8702
--- /dev/null
+++ b/test/api/models/h_deep_nesting.js
@@ -0,0 +1,48 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var CourseTeachersSchema = new Schema({
+ teacher: { type: Schema.Types.ObjectId, ref: 'b_using_options'},
+ room: Number
+});
+
+var ExamsSchema = new Schema({
+ subject: { type: String},
+ examDate: Date,
+ score: Number,
+ result: {type: String, enum: ['distinction', 'merit', 'pass', 'fail']},
+ grader: { type: Schema.Types.ObjectId, ref: 'b_using_options'}
+});
+
+var CourseSchema = new Schema({
+ subject: String,
+ grade: {type: String},
+ teachers: [CourseTeachersSchema]
+});
+
+var HSchema = new Schema({
+ surname: {type: String, list: {}, index: true},
+ forename: {type: String, list: true},
+ address: {
+ street: String,
+ town: String
+ },
+ studies: {
+ courses: {type: [CourseSchema], form: {noRemove: true}},
+ exams: [ExamsSchema]
+ },
+ assistants: [
+ { type: Schema.Types.ObjectId, ref: 'b_using_options'}
+ ]
+});
+
+var H;
+try {
+ H = mongoose.model('H');
+} catch (e) {
+ H = mongoose.model('H', HSchema);
+}
+
+module.exports = H;
+
diff --git a/test/api/models/i_tabbed_forms.js b/test/api/models/i_tabbed_forms.js
new file mode 100644
index 00000000..84fa0d59
--- /dev/null
+++ b/test/api/models/i_tabbed_forms.js
@@ -0,0 +1,29 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var ISchema = new Schema({
+ surname: {type: String, required: true, list: {}, form: {tab: 'first'}, index: true},
+ forename: {type: String, list: true, form: {tab: 'first'}},
+ address: {
+ line1: {type: String, form: {label: 'Address', tab: 'first'}},
+ line2: {type: String, form: {label: null, tab: 'first'}},
+ line3: {type: String, form: {label: null, tab: 'first'}},
+ town: {type: String, form: {label: 'Town', tab: 'first'}},
+ postcode: {type: String, form: {label: 'Postcode', tab: 'first'}}
+ },
+ weight: {type: Number, form: {label: 'Weight (lbs)', tab: 'second'}},
+ dateOfBirth: {type: Date, form: {tab: 'second'}},
+ accepted: {type: Boolean, form: {tab: 'second'}},
+ interviewScore: {type: Number, form: {tab: 'second'}, list: {}},
+ freeText: {type: String, form: {type: 'textarea', rows: 5, tab: 'second'}}
+});
+
+var I;
+try {
+ I = mongoose.model('I');
+} catch (e) {
+ I = mongoose.model('I', ISchema);
+}
+
+module.exports = I;
diff --git a/test/api/models/j_directive_with_form.js b/test/api/models/j_directive_with_form.js
new file mode 100644
index 00000000..4ac616f6
--- /dev/null
+++ b/test/api/models/j_directive_with_form.js
@@ -0,0 +1,25 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var FriendSchema = new Schema({
+ friend: { type: Schema.Types.ObjectId, ref: 'a_unadorned_mongoose'},
+ type: { type: String, enum: ['best friend', 'partner', 'colleague', 'acquaintance', 'other']},
+ comment: { type: String}
+}, {_id: false});
+
+var JSchema = new Schema({
+ surname: {type: String, required: true, list: {}, index: true},
+ forename: {type: String, list: true},
+ friendList: {type: [FriendSchema], form: {directive: 'friends'}}
+});
+
+var J;
+try {
+ J = mongoose.model('J');
+} catch (e) {
+ J = mongoose.model('J', JSchema);
+}
+
+module.exports = J;
+
diff --git a/test/api/models/z_custom_form.js b/test/api/models/z_custom_form.js
new file mode 100644
index 00000000..3ac05ee6
--- /dev/null
+++ b/test/api/models/z_custom_form.js
@@ -0,0 +1,20 @@
+'use strict';
+var mongoose = require('mongoose');
+var Schema = mongoose.Schema;
+
+var ZSchema = new Schema({
+ surname: {type: String, index: true},
+ forename: String,
+ weight: Number,
+ dateOfBirth: Date,
+ termsAccepted: Boolean
+});
+
+var Z;
+try {
+ Z = mongoose.model('Z');
+} catch (e) {
+ Z = mongoose.model('Z', ZSchema);
+}
+
+module.exports = Z;
diff --git a/test/api/report-api.js b/test/api/report-api.js
deleted file mode 100644
index 7579b881..00000000
--- a/test/api/report-api.js
+++ /dev/null
@@ -1,106 +0,0 @@
-var exec = require('child_process').exec
- , _ = require('underscore')
- , assert = require('assert')
- , mongoose = require('mongoose');
-
-describe('Report API', function () {
-
- it('handles pipeline request', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields?r=%7B%22pipeline%22:%7B%22%24group%22:%7B%22_id%22:%22%24sex%22,%22count%22:%7B%22%24sum%22:1%7D%7D%7D%7D', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 2);
- assert.deepEqual(data[0],{_id:'F',count:11});
- assert.deepEqual(data[1],{_id:'M',count:6});
- done();
- });
- });
-
- it('handles complex pipeline request', function(done) {
- exec('curl 0.0.0.0:3001/api/report/e_referencing_another_collection?r=%7B%22pipeline%22:%5B%7B%22%24group%22:%7B%22_id%22:%22%24teacher%22,%22count%22:%7B%22%24sum%22:1%7D%7D%7D%5D,%22title%22:%22Class%20Sizes%22,%22columnDefs%22:%5B%7B%22field%22:%22_id%22,%22displayName%22:%22Teacher%22%7D,%7B%22field%22:%22count%22,%22displayName%22:%22Number%20in%20Class%22%7D%5D,%22columnTranslations%22:%5B%7B%22field%22:%22_id%22,%22ref%22:%22b_using_options%22%7D%5D%7D', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:'IsAccepted John true 89',count:1});
- done();
- });
- });
-
- it('looks up schema and does a simple translate', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields/breakdownbysex', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 2);
- assert.deepEqual(data[0],{_id:'Female',count:11});
- assert.deepEqual(data[1],{_id:'Male',count:6});
- done();
- });
- });
-
- it('supports functions in column translate', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields/functiondemo', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 2);
- assert.deepEqual(data[0],{_id:'Female',count:11, functionResult:21});
- assert.deepEqual(data[1],{_id:'Male',count:6, functionResult:16});
- done();
- });
- });
-
- it('looks up schema and does a table lookup', function(done) {
- exec('curl 0.0.0.0:3001/api/report/e_referencing_another_collection/class-sizes', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:'IsAccepted John true 89',count:1});
- done();
- });
- });
-
- it('handles invalid lookup table error', function(done) {
- exec('curl 0.0.0.0:3001/api/report/e_referencing_another_collection?r=%7B%22pipeline%22:%5B%7B%22%24group%22:%7B%22_id%22:%22%24teacher%22,%22count%22:%7B%22%24sum%22:1%7D%7D%7D%5D,%22title%22:%22Class%20Sizes%22,%22columnDefs%22:%5B%7B%22field%22:%22_id%22,%22displayName%22:%22Teacher%22%7D,%7B%22field%22:%22count%22,%22displayName%22:%22Number%20in%20Class%22%7D%5D,%22columnTranslations%22:%5B%7B%22field%22:%22_id%22,%22ref%22:%22b_usissng_options%22%7D%5D%7D', function (error, stdout) {
- assert.equal(stdout,"Invalid ref property of b_usissng_options in columnTranslations _id");
- done();
- });
- });
-
- it('supports selection by text parameter', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields/totalforonesex', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:'Male',count:6});
- done();
- });
- });
-
- it('supports selection by query text parameter', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields/totalforonesex?sex=F', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:'Female',count:11});
- done();
- });
- });
-
- it('supports selection by numeric parameter', function(done) {
- exec('curl 0.0.0.0:3001/api/report/g_conditional_fields/selectbynumber?number_param=11', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:'F',count:11});
- done();
- });
- });
-
- it('honours findfunc',function(done) {
- exec('curl 0.0.0.0:3001/api/report/b_using_options/allVisible', function (error, stdout) {
- var data = JSON.parse(stdout).report;
- assert.equal(data.length, 1);
- assert.deepEqual(data[0],{_id:true,count:2});
- done();
- });
- });
-
- it('prevents access to secure fields', function(done) {
- exec('curl 0.0.0.0:3001/api/report/b_using_options?r=%5B%7B%22$project%22:%7B%22passwordHash%22:1%7D%7D%5D', function (error, stdout) {
- assert.equal(stdout, 'You cannot access passwordHash');
- done();
- });
- })
-});
-
diff --git a/test/api/reportAPISpec.js b/test/api/reportAPISpec.js
new file mode 100644
index 00000000..60a60b5d
--- /dev/null
+++ b/test/api/reportAPISpec.js
@@ -0,0 +1,293 @@
+'use strict';
+
+var assert = require('assert');
+var formsAngular = require('../../dist/server/data_form.js');
+var express = require('express');
+var async = require('async');
+var path = require('path');
+var fs = require('fs');
+var exec = require('child_process').exec;
+var mongoose = require('mongoose');
+
+describe('Report API', function () {
+
+ var fng, app;
+
+ before(function (done) {
+ app = express();
+
+ fng = new (formsAngular)(mongoose, app, {urlPrefix: '/api/'});
+
+ mongoose.connect('mongodb://localhost/forms-ng_test', {useMongoClient: true});
+ mongoose.connection.on('error', function () {
+ console.error('connection error', arguments);
+ });
+
+ mongoose.connection.on('open', function () {
+ // Bootstrap models
+ var modelsPath = path.join(__dirname, '/models');
+ fs.readdirSync(modelsPath).forEach(function (file) {
+ var fname = modelsPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ fng.addResource(file.slice(0, -3), require(fname), {suppressDeprecatedMessage: true});
+ }
+ });
+ });
+
+ // Import test data
+ var dataPath = path.join(__dirname, 'data');
+ async.each(fs.readdirSync(dataPath), function (file, callback) {
+ var fname = dataPath + '/' + file;
+ if (fs.statSync(fname).isFile()) {
+ exec('mongoimport --db forms-ng_test --drop --collection ' + file.slice(0, 1) + 's --jsonArray < ' + fname, callback);
+ }
+ }, function (err) {
+ if (err) {
+ console.log('Problem importing test data ' + err.message);
+ } else {
+ done();
+ }
+ });
+ });
+
+ after(function (done) {
+ mongoose.connection.db.dropDatabase(function () {
+ mongoose.disconnect(function () {
+ done();
+ });
+ });
+ });
+
+ it('handles pipeline request', function (done) {
+ var mockReq = {
+ url: '/report/g_conditional_fields',
+ query: {r:'{"pipeline":{"$group":{"_id":"x","count":{"$sum":1}}}}'},
+ params: {resourceName: 'g_conditional_fields'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'x', count: 17});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('handles complex pipeline request', function (done) {
+ var mockReq = {
+ url: 'report/e_referencing_another_collection',
+ query: {r:'{"pipeline":[{"$group":{"_id":"$teacher","count":{"$' +
+ 'sum":1}}}],"title":"Class Sizes","columnDefs":[{"field":"_id","displayName":"Teacher"},{"field":"' +
+ 'count","displayName":"Number in Class"}],"columnTranslations":[{"field":"_id","ref":"b_using_options"}]}'},
+ params: {resourceName: 'e_referencing_another_collection'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'IsAccepted2 Johan true 89', count: 1});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('looks up schema and does a simple translate', function (done) {
+ var mockReq = {
+ url: 'report/g_conditional_fields/breakdownbysex',
+ params : {
+ resourceName: 'g_conditional_fields',
+ reportName: 'breakdownbysex'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 2);
+ assert.deepEqual(data.report[0], {_id: 'Female', count: 11});
+ assert.deepEqual(data.report[1], {_id: 'Male', count: 6});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports two reference lookups', function (done) {
+ var reportSpec = {
+ 'pipeline': [{'$project': {'surname': 1, 'forename': 1, 'teacher': 1, 'mentor': 1}}],
+ 'title': 'Class Sizes',
+ 'columnTranslations': [{'field': 'teacher', 'ref': 'b_using_options'}, {'field': 'mentor', 'ref': 'c_subdoc_example'}]
+ };
+ var mockReq = {
+ url: 'report/e_referencing_another_collection',
+ query: {r : JSON.stringify(reportSpec)},
+ params: {resourceName: 'e_referencing_another_collection'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.equal(data.report[0].surname, 'Smith');
+ assert.equal(data.report[0].forename, 'John');
+ assert.equal(data.report[0].teacher, 'IsAccepted2 Johan true 89');
+ assert.equal(data.report[0].mentor, 'Anderson John');
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports functions in column translate', function (done) {
+ var mockReq = {
+ url: 'report/g_conditional_fields/functiondemo',
+ params : {
+ resourceName: 'g_conditional_fields',
+ reportName: 'functiondemo'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 2);
+ assert.deepEqual(data.report[0], {_id: 'Female', count: 11, functionResult: 21});
+ assert.deepEqual(data.report[1], {_id: 'Male', count: 6, functionResult: 16});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('looks up schema and does a table lookup', function (done) {
+ var mockReq = {
+ url: 'report/e_referencing_another_collection/class-sizes',
+ params : {
+ resourceName: 'e_referencing_another_collection',
+ reportName: 'class-sizes'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'IsAccepted2 Johan true 89', count: 1});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('handles invalid lookup table error', function (done) {
+ var mockReq = {
+ url: 'report/e_referencing_another_collection',
+ query: {r: '{"pipeline":[{"$group":{"' +
+ '_id":"$teacher","count":{"$sum":1}}}],"title":"Class Sizes","columnDefs' +
+ '":[{"field":"_id","displayName":"Teacher"},{"field":"count","displayName":"' +
+ 'Number in Class"}],"columnTranslations":[{"field":"_id","ref":"b_usissng_options' +
+ '"}]}'},
+ params : {resourceName: 'g_conditional_fields'}
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data, 'Invalid ref property of b_usissng_options in columnTranslations _id');
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports selection by text parameter', function (done) {
+ var mockReq = {
+ url: 'report/g_conditional_fields/totalforonesex',
+ params : {
+ resourceName: 'g_conditional_fields',
+ reportName: 'totalforonesex'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'Male', count: 6});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports selection by query text parameter', function (done) {
+ var mockReq = {
+ query: {sex: 'F'},
+ url: 'report/g_conditional_fields/totalforonesex',
+ params : {
+ resourceName: 'g_conditional_fields',
+ reportName: 'totalforonesex'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'Female', count: 11});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports selection by numeric parameter', function (done) {
+ var mockReq = {
+ url: 'report/g_conditional_fields/selectbynumber',
+ query:{
+ number_param:11
+ },
+ params : {
+ resourceName: 'g_conditional_fields',
+ reportName: 'selectbynumber'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: 'F', count: 11});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('honours findfunc', function (done) {
+ var mockReq = {
+ url: 'report/b_using_options/allVisible',
+ params : {
+ resourceName: 'b_using_options',
+ reportName: 'allVisible'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data.report.length, 1);
+ assert.deepEqual(data.report[0], {_id: true, count: 2});
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('prevents access to secure fields', function (done) {
+ var mockReq = {
+ url: 'report/b_using_options',
+ query: {
+ r: '[{"$project":{"passwordHash":1}}]'
+ },
+ params : {
+ resourceName: 'b_using_options'
+ }
+ };
+ var mockRes = {
+ send: function (data) {
+ assert.equal(data, 'You cannot access passwordHash');
+ done();
+ }
+ };
+ fng.report()(mockReq, mockRes);
+ });
+
+ it('supports lookups where the list item is a lookup', function() {
+
+ });
+
+});
diff --git a/test/e2e/base_edit_form.js b/test/e2e/base_edit_form.js
deleted file mode 100644
index 965ceb4f..00000000
--- a/test/e2e/base_edit_form.js
+++ /dev/null
@@ -1,115 +0,0 @@
-'use strict';
-
-describe('Base edit form', function() {
-
- it('should display a form', function () {
- browser().navigateTo('/#!/b_using_options/new');
- expect( element('div#cg_f_surname').text() ).
- toMatch( /Surname/ );
- });
-
- it('should display an error message if server validation fails', function() {
- browser().navigateTo('/#!/b_using_options/new');
- input('record.surname').enter('Smith');
- input('record.accepted').check();
- input('record.freeText').enter('this is a rude word');
- element('#saveButton').click();
- expect( element('.alert-error').text()).toMatch(/Error!/);
- expect( element('.alert-error').text()).toMatch(/Wash your mouth!/);
- expect( element('.alert-error').text()).not().toMatch(/eye/);
- });
-
- describe('should display deletion confirmation modal', function() {
-
- beforeEach(function () {
-
- browser().navigateTo('/#!/a_unadorned_mongoose/666a6075b320153869b17599/edit');
- });
-
- it('should display deletion confirmation modal', function() {
-
- element('#deleteButton').click();
- expect( element('.modal').count() ).toEqual(1);
- });
-
- });
-
- describe('Allows user to navigate away',function() {
-
- it('does not put up dialog if no changes',function() {
- browser().navigateTo('/#!/a_unadorned_mongoose/666a6075b320153869b17599/edit');
- element('#newButton').click();
- expect(browser().location().url()).toMatch("/a_unadorned_mongoose/new");
- });
-
- });
-
- describe('prompts user to save changes',function() {
-
- beforeEach(function() {
- browser().navigateTo('/#!/b_using_options/519a6075b320153869b155e0/edit');
- input('record.freeText').enter('This is a rude thing');
- element('#newButton').click();
- });
-
- it('supports cancelling navigation', function() {
- expect( element('.modal').count() ).toEqual(1);
- element('.modal-footer button.dlg-cancel').click();
- expect(browser().location().url()).toMatch("/b_using_options/519a6075b320153869b155e0/edit");
- expect( element('.modal').count() ).toEqual(0);
- });
-
- it('supports losing changes', function() {
- element('.modal-footer button.dlg-no').click();
- expect(browser().location().url()).toMatch("/b_using_options/new");
- expect( element('.modal').count() ).toEqual(0);
- });
-
- it('supports saving changes', function() {
- element('.modal-footer button.dlg-yes').click();
- expect( element('.alert-error').text()).toMatch(/your mouth/);
- expect( element('.modal').count() ).toEqual(0);
- input('record.freeText').enter('This is a polite thing ' + new Date().getTime()); // to ensure that it is a change
- element('#newButton').click();
- expect( element('.modal').count() ).toEqual(1);
- element('.modal-footer button.dlg-yes').click();
- expect(browser().location().url()).toMatch("/b_using_options/new");
- browser().navigateTo('/#!/b_using_options/519a6075b320153869b155e0/edit');
- expect(element('#f_freeText').val()).toMatch(/polite thing/);
- });
- });
-
- describe('form button changes',function() {
-
- it('enables cancel button after a change', function() {
- browser().navigateTo('/#!/b_using_options/new');
- input('record.surname').enter('Smith');
- expect( element('#f_surname').val() ).toMatch( /Smith/ );
- element('#cancelButton').click();
- expect( element('#f_surname').val() ).not().toMatch( /Smith/ );
- });
-
- it('enables cancel button after deleting an array element', function() {
- browser().navigateTo('/#!/d_array_example/51a6182aea4ea77715000005/edit');
- expect(repeater('.fng-array').count()).toEqual(1);
- element('#remove_f_specialSubjects_0').click();
- expect(repeater('.fng-array').count()).toEqual(0);
- element('#saveButton').click();
- browser().navigateTo('/#!/d_array_example/51a6182aea4ea77715000005/edit');
- expect(repeater('.fng-array').count()).toEqual(0);
- });
-
- });
-
- describe('tab sets', function() {
-
- it('shows multiple tabs when appropriate',function() {
- browser().navigateTo('/#!/i_tabbed_forms/new');
- element('a:contains("first")').click();
- element('a:contains("second")').click();
- })
-
- })
-
-});
-
diff --git a/test/e2e/base_list.js b/test/e2e/base_list.js
deleted file mode 100644
index 180926b2..00000000
--- a/test/e2e/base_list.js
+++ /dev/null
@@ -1,39 +0,0 @@
-'use strict';
-
-describe('Base list', function() {
-
- it('should list all the records', function () {
- browser().navigateTo('/#!/a_unadorned_mongoose');
- expect(element('a').text()).toMatch( /TestPerson1/ );
- });
-
- it('should support the listOrder option', function() {
- browser().navigateTo('/#!/g_conditional_fields');
- expect(repeater('.list-item').count()).toBeGreaterThan(8);
- expect(element('.list-item>.span6:first-child').text()).not().toMatch('Smith05 Smith06 Smith97 Smith08');
- });
-
- it('should support the model name override', function() {
- browser().navigateTo('/#!/h_deep_nesting');
- expect(element('h1').text()).toMatch(/^Nesting /);
- });
-
- it('should support dropdown text override', function() {
- browser().navigateTo('/#!/b_using_options');
- expect(element('li.dropdown').text()).toMatch('Custom Dropdown');
- });
-
- // this test doesn't fail when it should...
- it('should revert to normal model descriptions', function() {
- browser().navigateTo('/#!/d_array_example');
- expect(element('h1').text()).toMatch('D Array Example');
- });
-
- it('should support the model name override with bespoke formschema', function() {
- browser().navigateTo('/#!/b_using_options/justnameandpostcode');
- expect(element('h1').text()).toMatch('Another override');
- expect(element('li.dropdown').text()).toMatch('Custom 2nd Level');
- });
-
-});
-
diff --git a/test/e2e/conditionals.js b/test/e2e/conditionals.js
deleted file mode 100644
index 3a292945..00000000
--- a/test/e2e/conditionals.js
+++ /dev/null
@@ -1,18 +0,0 @@
-'use strict';
-
-describe('Conditionals', function() {
-
- it('should not show hidden fields', function () {
- browser().navigateTo('/#!/g_conditional_fields/51c583d5b9991226db418f00/edit');
- expect( element('.hasDatepicker:visible').count() ).toBe(0);
- input('record.accepted').check();
- expect( element('.hasDatepicker:visible').count() ).toBe(1);
- });
-
- it('should not show hidden fields in sub schemas', function () {
- browser().navigateTo('/#!/f_nested_schema/51c583d5b5c51226db418f17/edit');
- expect( element('.hasDatepicker:visible').count() ).toBe(4);
- });
-
-});
-
diff --git a/test/e2e/demo.js b/test/e2e/demo.js
deleted file mode 100644
index bb1d7430..00000000
--- a/test/e2e/demo.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use strict';
-
-describe('Forms app demo', function() {
-
- it('should automatically redirect to index when location hash/fragment is empty', function () {
- browser().navigateTo('/');
- expect(browser().window().hash()).toMatch('\/index');
- });
-
-});
diff --git a/test/e2e/events.js b/test/e2e/events.js
deleted file mode 100644
index 976a63b8..00000000
--- a/test/e2e/events.js
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-
-describe('Events', function() {
-
- it('should get an event from form input', function () {
- // this tests the event handling between form-input directive and that it works with a select2 control
- browser().navigateTo('/#!/b_using_options/519a6075b320153869b175e0/edit');
- expect( element( '#cg_f_eyeColour' ).css('background-color')).toEqual("rgb(109, 219, 79)");
- });
-
-});
\ No newline at end of file
diff --git a/test/e2e/find_functions.js b/test/e2e/find_functions.js
deleted file mode 100644
index 918d8d17..00000000
--- a/test/e2e/find_functions.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-
-describe('Find functions', function() {
-
- it('should find only the allowed records', function () {
- browser().navigateTo('/#!/b_using_options');
- expect( repeater( '.list-item' ).count() ).toEqual(2);
- expect( element('a').text() ).toMatch(/IsAccepted/);
- expect( element('a').text() ).not().toMatch(/NotAccepted/);
- });
-
- it('should support filters', function () {
- browser().navigateTo('/#!/a_unadorned_mongoose?f=%7B%22eyeColour%22:%22Blue%22%7D');
- expect( repeater( '.list-item' ).count() ).toEqual(1);
- expect( element('a').text() ).toMatch(/TestPerson1/);
- expect( element('a').text() ).not().toMatch(/TestPerson2/);
- });
-
-});
diff --git a/test/e2e/navigation.js b/test/e2e/navigation.js
deleted file mode 100644
index 3c011187..00000000
--- a/test/e2e/navigation.js
+++ /dev/null
@@ -1,29 +0,0 @@
-'use strict';
-
-describe('Navigation', function() {
-
- var baseMenuCount = 5;
-
- it('should cope with a list with menu options', function () {
- browser().navigateTo('/#!/b_using_options');
- expect( repeater( '.dropdown-option' ).count() ).toEqual(1 + baseMenuCount);
- });
-
- it('should cope with a list without menu options', function () {
- browser().navigateTo('/#!/d_array_example');
- expect( repeater( '.dropdown-option' ).count() ).toEqual(0 + baseMenuCount);
- });
-
- it('should cope with an edit screen with menu options', function () {
- browser().navigateTo('/#!/b_using_options/519a6075b320153869b175e0/edit');
- expect( repeater( '.dropdown-option' ).count() ).toEqual(2 + baseMenuCount);
- });
-
-
- it('should cope with an edit screen with menu options', function () {
- browser().navigateTo('/#!/a_unadorned_mongoose/519a6075b320153869b17599/edit');
- expect( repeater( '.dropdown-option' ).count() ).toEqual(0 + baseMenuCount);
- });
-
-});
-
diff --git a/test/e2e/reports.js b/test/e2e/reports.js
deleted file mode 100644
index 9472ddb9..00000000
--- a/test/e2e/reports.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-
-describe('Reports', function() {
-
- it('should do simple pipeline reports', function () {
- browser().navigateTo('/#!/analyse/g_conditional_fields?r=%5B%7B%22$group%22:%7B%22_id%22:%22$sex%22,%22count%22:%7B%22$sum%22:1%7D%7D%7D%5D');
- expect(element('.col1').text()).toMatch(/count/);
- expect(element('.col1').text()).toMatch(/11/);
- });
-
- it('should do reports with options from the command line', function() {
- browser().navigateTo('/#!/analyse/g_conditional_fields?r=%7B%22pipeline%22:%5B%7B%22$group%22:%7B%22_id%22:%22$sex%22,%22count%22:%7B%22$sum%22:1%7D%7D%7D%5D,%22title%22:%22Breakdown%20By%20Sex%22,%22columnDefs%22:%5B%7B%22field%22:%22_id%22,%22displayName%22:%22Sex%22%7D,%7B%22field%22:%22count%22,%22displayName%22:%22No%20of%20Applicants%22%7D%5D%7D');
- expect(element('.col1').text()).toMatch(/No of Applicants/);
- expect(element('.col1').text()).toMatch(/11/);
- });
-
- it('should generate a default report', function() {
- browser().navigateTo('/#!/analyse/b_using_options');
- expect(repeater('.ngRow').count()).toEqual(2);
- element('.ngRow').click();
- expect(browser().window().hash()).toMatch('\/b_using_options/519a6075b320153869b155e0/edit');
- })
-});
diff --git a/test/e2e/select2.js b/test/e2e/select2.js
deleted file mode 100644
index 0bc7dbea..00000000
--- a/test/e2e/select2.js
+++ /dev/null
@@ -1,29 +0,0 @@
-'use strict';
-
-describe('Select 2', function() {
-
- it('should handle enums', function () {
- browser().navigateTo('/#!/b_using_options/519a6075b320153869b155e0/edit');
- expect(element('#s2id_f_eyeColour').text()).toMatch(/Brown/);
- });
-
- it('should handle lookups with collection read', function () {
- browser().navigateTo('/#!/e_referencing_another_collection/51d1b2ca8c8683571c000005/edit');
- setTimeout(function(){
- expect(element('#s2id_f_teacher').text()).toMatch(/IsAccepted/);
-// element('#s2id_f_teacher').click();
-// setTimeout(function(){
-// expect(element('#select2-drop ul li:last').text()).toMatch(/Jones/);
-// element('#select2-drop ul li:last').click();
-// expect(element('#s2id_f_teacher').text()).toMatch(/Jones/);
-// },1);
- },0);
- });
-
- it('should handle lookups using Ajax', function () {
- browser().navigateTo('/#!/f_nested_schema/51c583d5b5c51226db418f16/edit');
- expect(element('#cg_f_exams_grader:first .select2-container').text()).toMatch(/IsAccepted/);
- });
-
-});
-
diff --git a/test/example-directives/bespoke-field-test.js b/test/example-directives/bespoke-field-test.js
new file mode 100644
index 00000000..0f8cd62c
--- /dev/null
+++ b/test/example-directives/bespoke-field-test.js
@@ -0,0 +1,52 @@
+'use strict';
+formsAngular.directive('emailField', ['$compile', '$filter', 'cssFrameworkService', function ($compile, $filter, cssFrameworkService) {
+ return {
+ restrict: 'E',
+ replace: true,
+ priority: 1,
+ compile: function () {
+ return function (scope, element, attrs) {
+ scope.$watch(attrs.formInput, function () {
+ var info = scope[attrs.schema],
+ template;
+ if (cssFrameworkService.framework() === 'bs2') {
+ template = '';
+ if (!info.label) {
+ info.label = $filter('titleCase')(info.name);
+ }
+ if (info.label !== '') {
+ template += '
' + info.label + ' ';
+ }
+ template += '
' +
+ '
' +
+ '@ ' +
+ ' ' +
+ '
' +
+ '
';
+ template += '
';
+ } else {
+ template = '';
+ }
+
+ element.replaceWith($compile(template)(scope));
+ });
+ };
+ }
+ };
+}]);
+
diff --git a/test/example-directives/friends.js b/test/example-directives/friends.js
new file mode 100644
index 00000000..ac385fb7
--- /dev/null
+++ b/test/example-directives/friends.js
@@ -0,0 +1,57 @@
+'use strict';
+formsAngular.controller('FriendCtrl', ['$scope', '$location', '$http', function ($scope, $location, $http) {
+ $scope.frdShowAdd = false;
+ $scope.frdNewFriend = {};
+ $scope.frdHideDetails = function () {
+ $scope.frdPopupName = 'Move mouse over a friend';
+ $scope.frdPopupPhone = 'to see their details';
+ };
+
+ $scope.frdShowDetails = function (friend) {
+ $http.get('/api/a_unadorned_mongoose/' + friend.friend).then(function (response) {
+ var data = response.data;
+ if (data && data.success !== false) {
+ $scope.frdPopupName = data.forename + ' ' + data.surname;
+ $scope.frdPopupPhone = data.phone;
+ } else {
+ $scope.frdPopupName = 'This friend does not exist - someone may have deleted the record';
+ }
+ }, function () {
+ $scope.frdPopupName = 'Error reading friend details';
+ $scope.frdPopupPhone = 'Please try again';
+ });
+ };
+
+ $scope.frdRemoveFriend = function (friend) {
+ for (var i = 0; i < $scope.record.friendList.length; i++) {
+ if ($scope.record.friendList[i].friend === friend.friend) {
+ $scope.record.friendList.splice(i, 1);
+ break;
+ }
+ }
+ };
+
+ $scope.frdShowAddForm = function () {
+ $scope.frdShowAdd = true;
+ $scope.frdNewFriend = {};
+ };
+
+ $scope.frdSaveFriend = function () {
+ var theFriend = angular.copy($scope.frdNewFriend.friendList);
+ delete theFriend.friend;
+ theFriend.friend = $scope.frdNewFriend.friendList.friend.id;
+ $scope.record.friendList.push(theFriend);
+ $scope.frdShowAdd = false;
+ };
+
+ $scope.frdHideDetails();
+
+}]).directive('friends', function () {
+ return {
+ restrict: 'E',
+ replace: true,
+ priority: 1,
+ controller: 'FriendCtrl',
+ templateUrl: 'test/template/friends.html'
+ };
+});
diff --git a/test/helpers/helpers.js b/test/helpers/helpers.js
new file mode 100644
index 00000000..c8700a62
--- /dev/null
+++ b/test/helpers/helpers.js
@@ -0,0 +1,114 @@
+'use strict';
+
+beforeEach(function () {
+ jasmine.addMatchers({
+ //toHaveClass: function (cls) {
+ // this.message = function () {
+ // return 'Expected "' + angular.mock.dump(this.actual) + '" to have class "' + cls + '".';
+ // };
+ //
+ // return this.actual.hasClass(cls);
+ //},
+ toHaveClass: function() {
+ return {
+ compare: function(actual, expected) {
+ var passed = actual.hasClass(expected);
+ return {
+ pass: passed,
+ message: 'Expected "' + angular.mock.dump(actual) + '" to have class "' + expected + '".'
+ };
+ }
+ };
+ },
+
+ //toHaveClassCount: function (cls, count) {
+ // this.message = function () {
+ // return 'Expected "' + angular.mock.dump(this.actual) + '" to have ' + count + ' instances of class "' + cls + '".';
+ // };
+ //
+ // for (var i = 0, classCount = 0; i < this.actual.length; i++) {
+ // var elm = angular.element(this.actual[i]);
+ // if (elm.hasClass(cls)) { classCount += 1; }
+ // }
+ //
+ // return (classCount === count);
+ //},
+ toHaveClassCount: function() {
+ return {
+ compare: function(actual, cls, expected) {
+ for (var i = 0, classCount = 0; i < actual.length; i++) {
+ var elm = angular.element(actual[i]);
+ if (elm.hasClass(cls)) { classCount += 1; }
+ }
+ var passed = (classCount === expected);
+
+ return {
+ pass: passed,
+ message: 'Expected "' + angular.mock.dump(actual) + '" to have ' + expected + ' instances of class "' + cls + '".'
+ };
+ }
+ };
+ },
+
+ //toHaveTypeCount: function (type, count) {
+ // this.message = function () {
+ // return 'Expected "' + angular.mock.dump(this.actual) + '" to have ' + count + ' instances of type "' + type + '".';
+ // };
+ //
+ // for (var i = 0, typeCount = 0; i < this.actual.length; i++) {
+ // var elm = angular.element(this.actual[i]);
+ // if (elm.attr('type') === type) { typeCount += 1; }
+ // }
+ //
+ // return (typeCount === count);
+ //},
+ toHaveTypeCount: function() {
+ return {
+ compare: function(actual, type, expected) {
+ for (var i = 0, typeCount = 0; i < actual.length; i++) {
+ var elm = angular.element(actual[i]);
+ if (elm.attr('type') === type) { typeCount += 1; }
+ }
+
+ var passed = (typeCount === expected);
+
+ return {
+ pass: passed,
+ message: 'Expected "' + angular.mock.dump(actual) + '" to have ' + expected + ' instances of type "' + type + '".'
+ };
+ }
+ };
+ },
+
+ //toHaveNameCount: function (name, count) {
+ // this.message = function () {
+ // return 'Expected "' + angular.mock.dump(this.actual) + '" to have ' + count + ' instances of name "' + name + '".';
+ // };
+ //
+ // for (var i = 0, nameCount = 0; i < this.actual.length; i++) {
+ // var elm = angular.element(this.actual[i]);
+ // if (elm.attr('name') === name) { nameCount += 1; }
+ // }
+ //
+ // return (nameCount === count);
+ //}
+ toHaveNameCount: function() {
+ return {
+ compare: function(actual, name, expected) {
+ for (var i = 0, nameCount = 0; i < actual.length; i++) {
+ var elm = angular.element(actual[i]);
+ if (elm.attr('name') === name) { nameCount += 1; }
+ }
+
+ var passed = (nameCount === expected);
+
+ return {
+ pass: passed,
+ message: 'Expected "' + angular.mock.dump(actual) + '" to have ' + expected + ' instances of name "' + name + '".'
+ };
+ }
+ };
+ }
+
+ });
+});
diff --git a/test/karma.conf.js b/test/karma.conf.js
new file mode 100644
index 00000000..f3734f83
--- /dev/null
+++ b/test/karma.conf.js
@@ -0,0 +1,64 @@
+module.exports = function(config) {
+ config.set({
+ basePath: '../',
+ frameworks: ['jasmine'],
+ files: [
+ "node_modules/angular/angular.js",
+ "node_modules/angular-sanitize/angular-sanitize.js",
+ "node_modules/lodash/lodash.js",
+ "node_modules/ng-infinite-scroll/build/ng-infinite-scroll.js",
+ 'node_modules/angular-mocks/angular-mocks.js',
+ 'node_modules/angular-messages/angular-messages.js',
+ 'node_modules/angular-elastic/elastic.js',
+ 'node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js',
+ 'dist/client/forms-angular.js',
+ 'src/client/template/*.html',
+ 'test/example-directives/*.js',
+ 'test/helpers/**/*.js',
+ 'test/unit/**/*.js'
+ ],
+
+ autoWatch : true,
+ usePolling: true,
+
+ customLaunchers: {
+ ChromeHeadless: {
+ base: 'Chrome',
+ flags: [
+ '--headless',
+ '--disable-gpu',
+ // Without a remote debugging port, Google Chrome exits immediately.
+ '--remote-debugging-port=9222'
+ ]
+ }
+ },
+
+ browsers : ['ChromeHeadless'],
+ // browsers : ['Firefox', 'ChromeHeadless'],
+
+ // use dots reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress'
+ // CLI --reporters progress
+ reporters: ['progress', 'junit'],
+
+ junitReporter: {
+ outputDir: 'test_out',
+ outputFile: 'test_out/unit.xml',
+ suite: 'unit'
+ },
+ plugins: [
+ 'karma-jasmine',
+ 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ 'karma-ng-html2js-preprocessor',
+ 'karma-junit-reporter'
+ ],
+ ngHtml2JsPreprocessor: {
+ // strip this from the file path
+ stripPrefix: 'src/client/'
+ },
+ preprocessors: {
+ 'src/client/template/*.html': 'ng-html2js'
+ }
+ });
+};
diff --git a/test/karma.midway.conf.js b/test/karma.midway.conf.js
new file mode 100644
index 00000000..e0332ce5
--- /dev/null
+++ b/test/karma.midway.conf.js
@@ -0,0 +1,69 @@
+module.exports = function(config) {
+ config.set({
+ basePath: '../',
+ frameworks: ['jasmine'],
+ files: [
+ "node_modules/angular/angular.js",
+ "node_modules/angular-sanitize/angular-sanitize.js",
+ "node_modules/lodash/lodash.js",
+ "node_modules/ng-infinite-scroll/build/ng-infinite-scroll.js",
+ 'node_modules/angular-mocks/angular-mocks.js',
+ 'node_modules/angular-messages/angular-messages.js',
+ 'node_modules/angular-elastic/elastic.js',
+ 'node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js',
+ 'dist/client/forms-angular.js',
+ 'src/client/template/*.html',
+ 'test/example-directives/*.js',
+ 'test/helpers/**/*.js',
+ 'test/template/*.html',
+ 'test/midway/**/*.js'
+ ],
+
+ client: {
+ captureConsole: true
+ },
+ autoWatch : true,
+ usePolling: true,
+
+ customLaunchers: {
+ ChromeHeadless: {
+ base: 'Chrome',
+ flags: [
+ '--headless',
+ '--disable-gpu',
+ // Without a remote debugging port, Google Chrome exits immediately.
+ '--remote-debugging-port=9222'
+ ]
+ }
+ },
+
+ browsers : ['ChromeHeadless'],
+ // browsers : ['Firefox', 'ChromeHeadless'],
+
+ // use dots reporter, as travis terminal does not support escaping sequences
+ // possible values: 'dots', 'progress'
+ // CLI --reporters progress
+ reporters: ['progress', 'junit'],
+
+ junitReporter: {
+ outputFile: 'test_out/unit.xml',
+ suite: 'midway'
+ },
+ plugins: [
+ 'karma-jasmine',
+ 'karma-chrome-launcher',
+ 'karma-firefox-launcher',
+ 'karma-ng-html2js-preprocessor',
+ 'karma-junit-reporter'
+ ],
+ ngHtml2JsPreprocessor: {
+ // strip this from the file path
+ stripPrefix: 'src/client/'
+ },
+ preprocessors: {
+ 'src/client/template/*.html': 'ng-html2js',
+ 'test/template/*.html': 'ng-html2js'
+ }
+ });
+};
+
diff --git a/test/lib/angular/angular-scenario.js b/test/lib/angular/angular-scenario.js
deleted file mode 100644
index 538a799d..00000000
--- a/test/lib/angular/angular-scenario.js
+++ /dev/null
@@ -1,26195 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.7.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Wed Mar 21 12:46:34 2012 -0700
- */
-(function( window, undefined ) {
-'use strict';
-
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document,
- navigator = window.navigator,
- location = window.location;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // A simple way to check for HTML strings or ID strings
- // Prioritize #id over to avoid XSS via location.hash (#9521)
- quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
- // Check if a string has a non-whitespace character in it
- rnotwhite = /\S/,
-
- // Used for trimming whitespace
- trimLeft = /^\s+/,
- trimRight = /\s+$/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
- // Useragent RegExp
- rwebkit = /(webkit)[ \/]([\w.]+)/,
- ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
- rmsie = /(msie) ([\w.]+)/,
- rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
-
- // Matches dashed string for camelizing
- rdashAlpha = /-([a-z]|[0-9])/ig,
- rmsPrefix = /^-ms-/,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return ( letter + "" ).toUpperCase();
- },
-
- // Keep a UserAgent string for use with jQuery.browser
- userAgent = navigator.userAgent,
-
- // For matching the engine and version of the browser
- browserMatch,
-
- // The deferred used on DOM ready
- readyList,
-
- // The ready event handler
- DOMContentLoaded,
-
- // Save a reference to some core methods
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- push = Array.prototype.push,
- slice = Array.prototype.slice,
- trim = String.prototype.trim,
- indexOf = Array.prototype.indexOf,
-
- // [[Class]] -> type pairs
- class2type = {};
-
-jQuery.fn = jQuery.prototype = {
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- var match, elem, ret, doc;
-
- // Handle $(""), $(null), or $(undefined)
- if ( !selector ) {
- return this;
- }
-
- // Handle $(DOMElement)
- if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
- }
-
- // The body element only exists once, optimize finding it
- if ( selector === "body" && !context && document.body ) {
- this.context = document;
- this[0] = document.body;
- this.selector = selector;
- this.length = 1;
- return this;
- }
-
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- // Are we dealing with HTML string or an ID?
- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
- // Assume that strings that start and end with <> are HTML and skip the regex check
- match = [ null, selector, null ];
-
- } else {
- match = quickExpr.exec( selector );
- }
-
- // Verify a match, and that no context was specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
- doc = ( context ? context.ownerDocument || context : document );
-
- // If a single string is passed in and it's a single tag
- // just do a createElement and skip the rest
- ret = rsingleTag.exec( selector );
-
- if ( ret ) {
- if ( jQuery.isPlainObject( context ) ) {
- selector = [ document.createElement( ret[1] ) ];
- jQuery.fn.attr.call( selector, context, true );
-
- } else {
- selector = [ doc.createElement( ret[1] ) ];
- }
-
- } else {
- ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
- selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
- }
-
- return jQuery.merge( this, selector );
-
- // HANDLE: $("#id")
- } else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
-
- // Otherwise, we inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
-
- this.context = document;
- this.selector = selector;
- return this;
- }
-
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
-
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The current version of jQuery being used
- jquery: "1.7.2",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- toArray: function() {
- return slice.call( this, 0 );
- },
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num == null ?
-
- // Return a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems, name, selector ) {
- // Build a new jQuery matched element set
- var ret = this.constructor();
-
- if ( jQuery.isArray( elems ) ) {
- push.apply( ret, elems );
-
- } else {
- jQuery.merge( ret, elems );
- }
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
-
- ret.context = this.context;
-
- if ( name === "find" ) {
- ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
- } else if ( name ) {
- ret.selector = this.selector + "." + name + "(" + selector + ")";
- }
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- ready: function( fn ) {
- // Attach the listeners
- jQuery.bindReady();
-
- // Add the callback
- readyList.add( fn );
-
- return this;
- },
-
- eq: function( i ) {
- i = +i;
- return i === -1 ?
- this.slice( i ) :
- this.slice( i, i + 1 );
- },
-
- first: function() {
- return this.eq( 0 );
- },
-
- last: function() {
- return this.eq( -1 );
- },
-
- slice: function() {
- return this.pushStack( slice.apply( this, arguments ),
- "slice", slice.call(arguments).join(",") );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: push,
- sort: [].sort,
- splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- target = this;
- --i;
- }
-
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
-
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
-
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
-
- // Never move original objects, clone them
- target[ name ] = jQuery.extend( deep, clone, copy );
-
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
- }
- }
-
- // Return the modified object
- return target;
-};
-
-jQuery.extend({
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // Is the DOM ready to be used? Set to true once it occurs.
- isReady: false,
-
- // A counter to track how many items to wait for before
- // the ready event fires. See #6781
- readyWait: 1,
-
- // Hold (or release) the ready event
- holdReady: function( hold ) {
- if ( hold ) {
- jQuery.readyWait++;
- } else {
- jQuery.ready( true );
- }
- },
-
- // Handle when the DOM is ready
- ready: function( wait ) {
- // Either a released hold or an DOMready/load event and not yet ready
- if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready, 1 );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.fireWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger( "ready" ).off( "ready" );
- }
- }
- },
-
- bindReady: function() {
- if ( readyList ) {
- return;
- }
-
- readyList = jQuery.Callbacks( "once memory" );
-
- // Catch cases where $(document).ready() is called after the
- // browser event has already occurred.
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- return setTimeout( jQuery.ready, 1 );
- }
-
- // Mozilla, Opera and webkit nightlies currently support this event
- if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", jQuery.ready, false );
-
- // If IE event model is used
- } else if ( document.attachEvent ) {
- // ensure firing before onload,
- // maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", jQuery.ready );
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var toplevel = false;
-
- try {
- toplevel = window.frameElement == null;
- } catch(e) {}
-
- if ( document.documentElement.doScroll && toplevel ) {
- doScrollCheck();
- }
- }
- },
-
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
- isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
- },
-
- isArray: Array.isArray || function( obj ) {
- return jQuery.type(obj) === "array";
- },
-
- isWindow: function( obj ) {
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ toString.call(obj) ] || "object";
- },
-
- isPlainObject: function( obj ) {
- // Must be an Object.
- // Because of IE, we also have to check the presence of the constructor property.
- // Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- try {
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !hasOwn.call(obj, "constructor") &&
- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
-
- var key;
- for ( key in obj ) {}
-
- return key === undefined || hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- for ( var name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- parseJSON: function( data ) {
- if ( typeof data !== "string" || !data ) {
- return null;
- }
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
-
- }
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- parseXML: function( data ) {
- if ( typeof data !== "string" || !data ) {
- return null;
- }
- var xml, tmp;
- try {
- if ( window.DOMParser ) { // Standard
- tmp = new DOMParser();
- xml = tmp.parseFromString( data , "text/xml" );
- } else { // IE
- xml = new ActiveXObject( "Microsoft.XMLDOM" );
- xml.async = "false";
- xml.loadXML( data );
- }
- } catch( e ) {
- xml = undefined;
- }
- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
- jQuery.error( "Invalid XML: " + data );
- }
- return xml;
- },
-
- noop: function() {},
-
- // Evaluates a script in a global context
- // Workarounds based on findings by Jim Driscoll
- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
- globalEval: function( data ) {
- if ( data && rnotwhite.test( data ) ) {
- // We use execScript on Internet Explorer
- // We use an anonymous function so that context is window
- // rather than jQuery in Firefox
- ( window.execScript || function( data ) {
- window[ "eval" ].call( window, data );
- } )( data );
- }
- },
-
- // Convert dashed to camelCase; used by the css and data modules
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
- },
-
- // args is for internal usage only
- each: function( object, callback, args ) {
- var name, i = 0,
- length = object.length,
- isObj = length === undefined || jQuery.isFunction( object );
-
- if ( args ) {
- if ( isObj ) {
- for ( name in object ) {
- if ( callback.apply( object[ name ], args ) === false ) {
- break;
- }
- }
- } else {
- for ( ; i < length; ) {
- if ( callback.apply( object[ i++ ], args ) === false ) {
- break;
- }
- }
- }
-
- // A special, fast, case for the most common use of each
- } else {
- if ( isObj ) {
- for ( name in object ) {
- if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
- break;
- }
- }
- } else {
- for ( ; i < length; ) {
- if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
- break;
- }
- }
- }
- }
-
- return object;
- },
-
- // Use native String.trim function wherever possible
- trim: trim ?
- function( text ) {
- return text == null ?
- "" :
- trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- function( text ) {
- return text == null ?
- "" :
- text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
- },
-
- // results is for internal usage only
- makeArray: function( array, results ) {
- var ret = results || [];
-
- if ( array != null ) {
- // The window, strings (and functions) also have 'length'
- // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
- var type = jQuery.type( array );
-
- if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
- push.call( ret, array );
- } else {
- jQuery.merge( ret, array );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, array, i ) {
- var len;
-
- if ( array ) {
- if ( indexOf ) {
- return indexOf.call( array, elem, i );
- }
-
- len = array.length;
- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
- for ( ; i < len; i++ ) {
- // Skip accessing in sparse arrays
- if ( i in array && array[ i ] === elem ) {
- return i;
- }
- }
- }
-
- return -1;
- },
-
- merge: function( first, second ) {
- var i = first.length,
- j = 0;
-
- if ( typeof second.length === "number" ) {
- for ( var l = second.length; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
-
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var ret = [], retVal;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( var i = 0, length = elems.length; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // arg is for internal usage only
- map: function( elems, callback, arg ) {
- var value, key, ret = [],
- i = 0,
- length = elems.length,
- // jquery objects are treated as arrays
- isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
-
- // Go through the array, translating each of the items to their
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( key in elems ) {
- value = callback( elems[ key ], key, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return ret.concat.apply( [], ret );
- },
-
- // A global GUID counter for objects
- guid: 1,
-
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- if ( typeof context === "string" ) {
- var tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- var args = slice.call( arguments, 2 ),
- proxy = function() {
- return fn.apply( context, args.concat( slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
-
- return proxy;
- },
-
- // Mutifunctional method to get and set values to a collection
- // The value/s can optionally be executed if it's a function
- access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
- var exec,
- bulk = key == null,
- i = 0,
- length = elems.length;
-
- // Sets many values
- if ( key && typeof key === "object" ) {
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
- }
- chainable = 1;
-
- // Sets one value
- } else if ( value !== undefined ) {
- // Optionally, function values get executed if exec is true
- exec = pass === undefined && jQuery.isFunction( value );
-
- if ( bulk ) {
- // Bulk operations only iterate when executing function values
- if ( exec ) {
- exec = fn;
- fn = function( elem, key, value ) {
- return exec.call( jQuery( elem ), value );
- };
-
- // Otherwise they run against the entire set
- } else {
- fn.call( elems, value );
- fn = null;
- }
- }
-
- if ( fn ) {
- for (; i < length; i++ ) {
- fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
- }
- }
-
- chainable = 1;
- }
-
- return chainable ?
- elems :
-
- // Gets
- bulk ?
- fn.call( elems ) :
- length ? fn( elems[0], key ) : emptyGet;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- },
-
- // Use of jQuery.browser is frowned upon.
- // More details: http://docs.jquery.com/Utilities/jQuery.browser
- uaMatch: function( ua ) {
- ua = ua.toLowerCase();
-
- var match = rwebkit.exec( ua ) ||
- ropera.exec( ua ) ||
- rmsie.exec( ua ) ||
- ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
- [];
-
- return { browser: match[1] || "", version: match[2] || "0" };
- },
-
- sub: function() {
- function jQuerySub( selector, context ) {
- return new jQuerySub.fn.init( selector, context );
- }
- jQuery.extend( true, jQuerySub, this );
- jQuerySub.superclass = this;
- jQuerySub.fn = jQuerySub.prototype = this();
- jQuerySub.fn.constructor = jQuerySub;
- jQuerySub.sub = this.sub;
- jQuerySub.fn.init = function init( selector, context ) {
- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
- context = jQuerySub( context );
- }
-
- return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
- };
- jQuerySub.fn.init.prototype = jQuerySub.fn;
- var rootjQuerySub = jQuerySub(document);
- return jQuerySub;
- },
-
- browser: {}
-});
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
- jQuery.browser[ browserMatch.browser ] = true;
- jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
- jQuery.browser.safari = true;
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
- trimLeft = /^[\s\xA0]+/;
- trimRight = /[\s\xA0]+$/;
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
- DOMContentLoaded = function() {
- document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
- jQuery.ready();
- };
-
-} else if ( document.attachEvent ) {
- DOMContentLoaded = function() {
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( document.readyState === "complete" ) {
- document.detachEvent( "onreadystatechange", DOMContentLoaded );
- jQuery.ready();
- }
- };
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
- if ( jQuery.isReady ) {
- return;
- }
-
- try {
- // If IE is used, use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- document.documentElement.doScroll("left");
- } catch(e) {
- setTimeout( doScrollCheck, 1 );
- return;
- }
-
- // and execute any waiting functions
- jQuery.ready();
-}
-
-return jQuery;
-
-})();
-
-
-// String to Object flags format cache
-var flagsCache = {};
-
-// Convert String-formatted flags into Object-formatted ones and store in cache
-function createFlags( flags ) {
- var object = flagsCache[ flags ] = {},
- i, length;
- flags = flags.split( /\s+/ );
- for ( i = 0, length = flags.length; i < length; i++ ) {
- object[ flags[i] ] = true;
- }
- return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- * flags: an optional list of space-separated flags that will change how
- * the callback list behaves
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible flags:
- *
- * once: will ensure the callback list can only be fired once (like a Deferred)
- *
- * memory: will keep track of previous values and will call any callback added
- * after the list has been fired right away with the latest "memorized"
- * values (like a Deferred)
- *
- * unique: will ensure a callback can only be added once (no duplicate in the list)
- *
- * stopOnFalse: interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( flags ) {
-
- // Convert flags from String-formatted to Object-formatted
- // (we check in cache first)
- flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
-
- var // Actual callback list
- list = [],
- // Stack of fire calls for repeatable lists
- stack = [],
- // Last fire value (for non-forgettable lists)
- memory,
- // Flag to know if list was already fired
- fired,
- // Flag to know if list is currently firing
- firing,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // Add one or several callbacks to the list
- add = function( args ) {
- var i,
- length,
- elem,
- type,
- actual;
- for ( i = 0, length = args.length; i < length; i++ ) {
- elem = args[ i ];
- type = jQuery.type( elem );
- if ( type === "array" ) {
- // Inspect recursively
- add( elem );
- } else if ( type === "function" ) {
- // Add if not in unique mode and callback is not in
- if ( !flags.unique || !self.has( elem ) ) {
- list.push( elem );
- }
- }
- }
- },
- // Fire callbacks
- fire = function( context, args ) {
- args = args || [];
- memory = !flags.memory || [ context, args ];
- fired = true;
- firing = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
- memory = true; // Mark as halted
- break;
- }
- }
- firing = false;
- if ( list ) {
- if ( !flags.once ) {
- if ( stack && stack.length ) {
- memory = stack.shift();
- self.fireWith( memory[ 0 ], memory[ 1 ] );
- }
- } else if ( memory === true ) {
- self.disable();
- } else {
- list = [];
- }
- }
- },
- // Actual Callbacks object
- self = {
- // Add a callback or a collection of callbacks to the list
- add: function() {
- if ( list ) {
- var length = list.length;
- add( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away, unless previous
- // firing was halted (stopOnFalse)
- } else if ( memory && memory !== true ) {
- firingStart = length;
- fire( memory[ 0 ], memory[ 1 ] );
- }
- }
- return this;
- },
- // Remove a callback from the list
- remove: function() {
- if ( list ) {
- var args = arguments,
- argIndex = 0,
- argLength = args.length;
- for ( ; argIndex < argLength ; argIndex++ ) {
- for ( var i = 0; i < list.length; i++ ) {
- if ( args[ argIndex ] === list[ i ] ) {
- // Handle firingIndex and firingLength
- if ( firing ) {
- if ( i <= firingLength ) {
- firingLength--;
- if ( i <= firingIndex ) {
- firingIndex--;
- }
- }
- }
- // Remove the element
- list.splice( i--, 1 );
- // If we have some unicity property then
- // we only need to do this once
- if ( flags.unique ) {
- break;
- }
- }
- }
- }
- }
- return this;
- },
- // Control if a given callback is in the list
- has: function( fn ) {
- if ( list ) {
- var i = 0,
- length = list.length;
- for ( ; i < length; i++ ) {
- if ( fn === list[ i ] ) {
- return true;
- }
- }
- }
- return false;
- },
- // Remove all callbacks from the list
- empty: function() {
- list = [];
- return this;
- },
- // Have the list do nothing anymore
- disable: function() {
- list = stack = memory = undefined;
- return this;
- },
- // Is it disabled?
- disabled: function() {
- return !list;
- },
- // Lock the list in its current state
- lock: function() {
- stack = undefined;
- if ( !memory || memory === true ) {
- self.disable();
- }
- return this;
- },
- // Is it locked?
- locked: function() {
- return !stack;
- },
- // Call all callbacks with the given context and arguments
- fireWith: function( context, args ) {
- if ( stack ) {
- if ( firing ) {
- if ( !flags.once ) {
- stack.push( [ context, args ] );
- }
- } else if ( !( flags.once && memory ) ) {
- fire( context, args );
- }
- }
- return this;
- },
- // Call all the callbacks with the given arguments
- fire: function() {
- self.fireWith( this, arguments );
- return this;
- },
- // To know if the callbacks have already been called at least once
- fired: function() {
- return !!fired;
- }
- };
-
- return self;
-};
-
-
-
-
-var // Static reference to slice
- sliceDeferred = [].slice;
-
-jQuery.extend({
-
- Deferred: function( func ) {
- var doneList = jQuery.Callbacks( "once memory" ),
- failList = jQuery.Callbacks( "once memory" ),
- progressList = jQuery.Callbacks( "memory" ),
- state = "pending",
- lists = {
- resolve: doneList,
- reject: failList,
- notify: progressList
- },
- promise = {
- done: doneList.add,
- fail: failList.add,
- progress: progressList.add,
-
- state: function() {
- return state;
- },
-
- // Deprecated
- isResolved: doneList.fired,
- isRejected: failList.fired,
-
- then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
- deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
- return this;
- },
- always: function() {
- deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
- return this;
- },
- pipe: function( fnDone, fnFail, fnProgress ) {
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( {
- done: [ fnDone, "resolve" ],
- fail: [ fnFail, "reject" ],
- progress: [ fnProgress, "notify" ]
- }, function( handler, data ) {
- var fn = data[ 0 ],
- action = data[ 1 ],
- returned;
- if ( jQuery.isFunction( fn ) ) {
- deferred[ handler ](function() {
- returned = fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
- } else {
- newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
- }
- });
- } else {
- deferred[ handler ]( newDefer[ action ] );
- }
- });
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- if ( obj == null ) {
- obj = promise;
- } else {
- for ( var key in promise ) {
- obj[ key ] = promise[ key ];
- }
- }
- return obj;
- }
- },
- deferred = promise.promise({}),
- key;
-
- for ( key in lists ) {
- deferred[ key ] = lists[ key ].fire;
- deferred[ key + "With" ] = lists[ key ].fireWith;
- }
-
- // Handle state
- deferred.done( function() {
- state = "resolved";
- }, failList.disable, progressList.lock ).fail( function() {
- state = "rejected";
- }, doneList.disable, progressList.lock );
-
- // Call given func if any
- if ( func ) {
- func.call( deferred, deferred );
- }
-
- // All done!
- return deferred;
- },
-
- // Deferred helper
- when: function( firstParam ) {
- var args = sliceDeferred.call( arguments, 0 ),
- i = 0,
- length = args.length,
- pValues = new Array( length ),
- count = length,
- pCount = length,
- deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
- firstParam :
- jQuery.Deferred(),
- promise = deferred.promise();
- function resolveFunc( i ) {
- return function( value ) {
- args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
- if ( !( --count ) ) {
- deferred.resolveWith( deferred, args );
- }
- };
- }
- function progressFunc( i ) {
- return function( value ) {
- pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
- deferred.notifyWith( promise, pValues );
- };
- }
- if ( length > 1 ) {
- for ( ; i < length; i++ ) {
- if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
- args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
- } else {
- --count;
- }
- }
- if ( !count ) {
- deferred.resolveWith( deferred, args );
- }
- } else if ( deferred !== firstParam ) {
- deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
- }
- return promise;
- }
-});
-
-
-
-
-jQuery.support = (function() {
-
- var support,
- all,
- a,
- select,
- opt,
- input,
- fragment,
- tds,
- events,
- eventName,
- i,
- isSupported,
- div = document.createElement( "div" ),
- documentElement = document.documentElement;
-
- // Preliminary tests
- div.setAttribute("className", "t");
- div.innerHTML = " a ";
-
- all = div.getElementsByTagName( "*" );
- a = div.getElementsByTagName( "a" )[ 0 ];
-
- // Can't get basic test support
- if ( !all || !all.length || !a ) {
- return {};
- }
-
- // First batch of supports tests
- select = document.createElement( "select" );
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName( "input" )[ 0 ];
-
- support = {
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: ( a.getAttribute("href") === "/a" ),
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.55/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Make sure that if no value is specified for a checkbox
- // that it defaults to "on".
- // (WebKit defaults to "" instead)
- checkOn: ( input.value === "on" ),
-
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- optSelected: opt.selected,
-
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // Tests for enctype support on a form(#6743)
- enctype: !!document.createElement("form").enctype,
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
-
- // Will be defined later
- submitBubbles: true,
- changeBubbles: true,
- focusinBubbles: false,
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true,
- pixelMargin: true
- };
-
- // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
- jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Test to see if it's possible to delete an expando from an element
- // Fails in Internet Explorer
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
- div.attachEvent( "onclick", function() {
- // Cloning a node shouldn't copy over any
- // bound event handlers (IE does this)
- support.noCloneEvent = false;
- });
- div.cloneNode( true ).fireEvent( "onclick" );
- }
-
- // Check if a radio maintains its value
- // after being appended to the DOM
- input = document.createElement("input");
- input.value = "t";
- input.setAttribute("type", "radio");
- support.radioValue = input.value === "t";
-
- input.setAttribute("checked", "checked");
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "name", "t" );
-
- div.appendChild( input );
- fragment = document.createDocumentFragment();
- fragment.appendChild( div.lastChild );
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- fragment.removeChild( input );
- fragment.appendChild( div );
-
- // Technique from Juriy Zaytsev
- // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
- // We only care about the case where non-standard event systems
- // are used, namely in IE. Short-circuiting here helps us to
- // avoid an eval call (in setAttribute) which can cause CSP
- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
- if ( div.attachEvent ) {
- for ( i in {
- submit: 1,
- change: 1,
- focusin: 1
- }) {
- eventName = "on" + i;
- isSupported = ( eventName in div );
- if ( !isSupported ) {
- div.setAttribute( eventName, "return;" );
- isSupported = ( typeof div[ eventName ] === "function" );
- }
- support[ i + "Bubbles" ] = isSupported;
- }
- }
-
- fragment.removeChild( div );
-
- // Null elements to avoid leaks in IE
- fragment = select = opt = div = input = null;
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, outer, inner, table, td, offsetSupport,
- marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
- paddingMarginBorderVisibility, paddingMarginBorder,
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- conMarginTop = 1;
- paddingMarginBorder = "padding:0;margin:0;border:";
- positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
- paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
- style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
- html = "" +
- "";
-
- container = document.createElement("div");
- container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
- body.insertBefore( container, body.firstChild );
-
- // Construct the test element
- div = document.createElement("div");
- container.appendChild( div );
-
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- // (only IE 8 fails this test)
- div.innerHTML = "";
- tds = div.getElementsByTagName( "td" );
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Check if empty table cells still have offsetWidth/Height
- // (IE <= 8 fail this test)
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. For more
- // info see bug #3333
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- if ( window.getComputedStyle ) {
- div.innerHTML = "";
- marginDiv = document.createElement( "div" );
- marginDiv.style.width = "0";
- marginDiv.style.marginRight = "0";
- div.style.width = "2px";
- div.appendChild( marginDiv );
- support.reliableMarginRight =
- ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
- }
-
- if ( typeof div.style.zoom !== "undefined" ) {
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- // (IE < 8 does this)
- div.innerHTML = "";
- div.style.width = div.style.padding = "1px";
- div.style.border = 0;
- div.style.overflow = "hidden";
- div.style.display = "inline";
- div.style.zoom = 1;
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Check if elements with layout shrink-wrap their children
- // (IE 6 does this)
- div.style.display = "block";
- div.style.overflow = "visible";
- div.innerHTML = "
";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
- }
-
- div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
- div.innerHTML = html;
-
- outer = div.firstChild;
- inner = outer.firstChild;
- td = outer.nextSibling.firstChild.firstChild;
-
- offsetSupport = {
- doesNotAddBorder: ( inner.offsetTop !== 5 ),
- doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
- };
-
- inner.style.position = "fixed";
- inner.style.top = "20px";
-
- // safari subtracts parent border width here which is 5px
- offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
- inner.style.position = inner.style.top = "";
-
- outer.style.overflow = "hidden";
- outer.style.position = "relative";
-
- offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
- offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
-
- if ( window.getComputedStyle ) {
- div.style.marginTop = "1%";
- support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
- }
-
- if ( typeof container.style.zoom !== "undefined" ) {
- container.style.zoom = 1;
- }
-
- body.removeChild( container );
- marginDiv = div = container = null;
-
- jQuery.extend( support, offsetSupport );
- });
-
- return support;
-})();
-
-
-
-
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
- rmultiDash = /([A-Z])/g;
-
-jQuery.extend({
- cache: {},
-
- // Please use with caution
- uuid: 0,
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
- },
-
- hasData: function( elem ) {
- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
- return !!elem && !isEmptyDataObject( elem );
- },
-
- data: function( elem, name, data, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var privateCache, thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
-
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
- isEvents = name === "events";
-
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
- return;
- }
-
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- elem[ internalKey ] = id = ++jQuery.uuid;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // Avoids exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
- }
-
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ] = jQuery.extend( cache[ id ], name );
- } else {
- cache[ id ].data = jQuery.extend( cache[ id ].data, name );
- }
- }
-
- privateCache = thisCache = cache[ id ];
-
- // jQuery data() is stored in a separate object inside the object's internal data
- // cache in order to avoid key collisions between internal data and user-defined
- // data.
- if ( !pvt ) {
- if ( !thisCache.data ) {
- thisCache.data = {};
- }
-
- thisCache = thisCache.data;
- }
-
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
-
- // Users should not attempt to inspect the internal events object using jQuery.data,
- // it is undocumented and subject to change. But does anyone listen? No.
- if ( isEvents && !thisCache[ name ] ) {
- return privateCache.events;
- }
-
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( getByName ) {
-
- // First Try to find as-is property data
- ret = thisCache[ name ];
-
- // Test for null|undefined property data
- if ( ret == null ) {
-
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
- }
- } else {
- ret = thisCache;
- }
-
- return ret;
- },
-
- removeData: function( elem, name, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, i, l,
-
- // Reference to internal data cache key
- internalKey = jQuery.expando,
-
- isNode = elem.nodeType,
-
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
-
- // See jQuery.data for more information
- id = isNode ? elem[ internalKey ] : internalKey;
-
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
- }
-
- if ( name ) {
-
- thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
- if ( thisCache ) {
-
- // Support array or space separated string names for data keys
- if ( !jQuery.isArray( name ) ) {
-
- // try the string as a key before any manipulation
- if ( name in thisCache ) {
- name = [ name ];
- } else {
-
- // split the camel cased version by spaces unless a key with the spaces exists
- name = jQuery.camelCase( name );
- if ( name in thisCache ) {
- name = [ name ];
- } else {
- name = name.split( " " );
- }
- }
- }
-
- for ( i = 0, l = name.length; i < l; i++ ) {
- delete thisCache[ name[i] ];
- }
-
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
- return;
- }
- }
- }
-
- // See jQuery.data for more information
- if ( !pvt ) {
- delete cache[ id ].data;
-
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject(cache[ id ]) ) {
- return;
- }
- }
-
- // Browsers that fail expando deletion also refuse to delete expandos on
- // the window, but it will allow it on all other JS objects; other browsers
- // don't care
- // Ensure that `cache` is not a window object #10080
- if ( jQuery.support.deleteExpando || !cache.setInterval ) {
- delete cache[ id ];
- } else {
- cache[ id ] = null;
- }
-
- // We destroyed the cache and need to eliminate the expando on the node to avoid
- // false lookups in the cache for entries that no longer exist
- if ( isNode ) {
- // IE does not allow us to delete expando properties from nodes,
- // nor does it have a removeAttribute function on Document nodes;
- // we must handle all of these cases
- if ( jQuery.support.deleteExpando ) {
- delete elem[ internalKey ];
- } else if ( elem.removeAttribute ) {
- elem.removeAttribute( internalKey );
- } else {
- elem[ internalKey ] = null;
- }
- }
- },
-
- // For internal use only.
- _data: function( elem, name, data ) {
- return jQuery.data( elem, name, data, true );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- if ( elem.nodeName ) {
- var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- if ( match ) {
- return !(match === true || elem.getAttribute("classid") !== match);
- }
- }
-
- return true;
- }
-});
-
-jQuery.fn.extend({
- data: function( key, value ) {
- var parts, part, attr, name, l,
- elem = this[0],
- i = 0,
- data = null;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attr = elem.attributes;
- for ( l = attr.length; i < l; i++ ) {
- name = attr[i].name;
-
- if ( name.indexOf( "data-" ) === 0 ) {
- name = jQuery.camelCase( name.substring(5) );
-
- dataAttr( elem, name, data[ name ] );
- }
- }
- jQuery._data( elem, "parsedAttrs", true );
- }
- }
-
- return data;
- }
-
- // Sets multiple values
- if ( typeof key === "object" ) {
- return this.each(function() {
- jQuery.data( this, key );
- });
- }
-
- parts = key.split( ".", 2 );
- parts[1] = parts[1] ? "." + parts[1] : "";
- part = parts[1] + "!";
-
- return jQuery.access( this, function( value ) {
-
- if ( value === undefined ) {
- data = this.triggerHandler( "getData" + part, [ parts[0] ] );
-
- // Try to fetch any internally stored data first
- if ( data === undefined && elem ) {
- data = jQuery.data( elem, key );
- data = dataAttr( elem, key, data );
- }
-
- return data === undefined && parts[1] ?
- this.data( parts[0] ) :
- data;
- }
-
- parts[1] = value;
- this.each(function() {
- var self = jQuery( this );
-
- self.triggerHandler( "setData" + part, parts );
- jQuery.data( this, key, value );
- self.triggerHandler( "changeData" + part, parts );
- });
- }, null, value, arguments.length > 1, null, false );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
-});
-
-function dataAttr( elem, key, data ) {
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
-
- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
- data = elem.getAttribute( name );
-
- if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- jQuery.isNumeric( data ) ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- jQuery.data( elem, key, data );
-
- } else {
- data = undefined;
- }
- }
-
- return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
- for ( var name in obj ) {
-
- // if the public data object is empty, the private is still empty
- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
- continue;
- }
- if ( name !== "toJSON" ) {
- return false;
- }
- }
-
- return true;
-}
-
-
-
-
-function handleQueueMarkDefer( elem, type, src ) {
- var deferDataKey = type + "defer",
- queueDataKey = type + "queue",
- markDataKey = type + "mark",
- defer = jQuery._data( elem, deferDataKey );
- if ( defer &&
- ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
- ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
- // Give room for hard-coded callbacks to fire first
- // and eventually mark/queue something else on the element
- setTimeout( function() {
- if ( !jQuery._data( elem, queueDataKey ) &&
- !jQuery._data( elem, markDataKey ) ) {
- jQuery.removeData( elem, deferDataKey, true );
- defer.fire();
- }
- }, 0 );
- }
-}
-
-jQuery.extend({
-
- _mark: function( elem, type ) {
- if ( elem ) {
- type = ( type || "fx" ) + "mark";
- jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
- }
- },
-
- _unmark: function( force, elem, type ) {
- if ( force !== true ) {
- type = elem;
- elem = force;
- force = false;
- }
- if ( elem ) {
- type = type || "fx";
- var key = type + "mark",
- count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
- if ( count ) {
- jQuery._data( elem, key, count );
- } else {
- jQuery.removeData( elem, key, true );
- handleQueueMarkDefer( elem, type, "mark" );
- }
- }
- },
-
- queue: function( elem, type, data ) {
- var q;
- if ( elem ) {
- type = ( type || "fx" ) + "queue";
- q = jQuery._data( elem, type );
-
- // Speed up dequeue by getting out quickly if this is just a lookup
- if ( data ) {
- if ( !q || jQuery.isArray(data) ) {
- q = jQuery._data( elem, type, jQuery.makeArray(data) );
- } else {
- q.push( data );
- }
- }
- return q || [];
- }
- },
-
- dequeue: function( elem, type ) {
- type = type || "fx";
-
- var queue = jQuery.queue( elem, type ),
- fn = queue.shift(),
- hooks = {};
-
- // If the fx queue is dequeued, always remove the progress sentinel
- if ( fn === "inprogress" ) {
- fn = queue.shift();
- }
-
- if ( fn ) {
- // Add a progress sentinel to prevent the fx queue from being
- // automatically dequeued
- if ( type === "fx" ) {
- queue.unshift( "inprogress" );
- }
-
- jQuery._data( elem, type + ".run", hooks );
- fn.call( elem, function() {
- jQuery.dequeue( elem, type );
- }, hooks );
- }
-
- if ( !queue.length ) {
- jQuery.removeData( elem, type + "queue " + type + ".run", true );
- handleQueueMarkDefer( elem, type, "queue" );
- }
- }
-});
-
-jQuery.fn.extend({
- queue: function( type, data ) {
- var setter = 2;
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- setter--;
- }
-
- if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
- }
-
- return data === undefined ?
- this :
- this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- dequeue: function( type ) {
- return this.each(function() {
- jQuery.dequeue( this, type );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
- type = type || "fx";
-
- return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
- hooks.stop = function() {
- clearTimeout( timeout );
- };
- });
- },
- clearQueue: function( type ) {
- return this.queue( type || "fx", [] );
- },
- // Get a promise resolved when queues of a certain type
- // are emptied (fx is the type by default)
- promise: function( type, object ) {
- if ( typeof type !== "string" ) {
- object = type;
- type = undefined;
- }
- type = type || "fx";
- var defer = jQuery.Deferred(),
- elements = this,
- i = elements.length,
- count = 1,
- deferDataKey = type + "defer",
- queueDataKey = type + "queue",
- markDataKey = type + "mark",
- tmp;
- function resolve() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- }
- while( i-- ) {
- if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
- ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
- jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
- jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
- count++;
- tmp.add( resolve );
- }
- }
- resolve();
- return defer.promise( object );
- }
-});
-
-
-
-
-var rclass = /[\n\t\r]/g,
- rspace = /\s+/,
- rreturn = /\r/g,
- rtype = /^(?:button|input)$/i,
- rfocusable = /^(?:button|input|object|select|textarea)$/i,
- rclickable = /^a(?:rea)?$/i,
- rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute,
- nodeHook, boolHook, fixSpecified;
-
-jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
- },
-
- removeProp: function( name ) {
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
- },
-
- addClass: function( value ) {
- var classNames, i, l, elem,
- setClass, c, cl;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call(this, j, this.className) );
- });
- }
-
- if ( value && typeof value === "string" ) {
- classNames = value.split( rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- elem = this[ i ];
-
- if ( elem.nodeType === 1 ) {
- if ( !elem.className && classNames.length === 1 ) {
- elem.className = value;
-
- } else {
- setClass = " " + elem.className + " ";
-
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
- setClass += classNames[ c ] + " ";
- }
- }
- elem.className = jQuery.trim( setClass );
- }
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classNames, i, l, elem, className, c, cl;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call(this, j, this.className) );
- });
- }
-
- if ( (value && typeof value === "string") || value === undefined ) {
- classNames = ( value || "" ).split( rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- elem = this[ i ];
-
- if ( elem.nodeType === 1 && elem.className ) {
- if ( value ) {
- className = (" " + elem.className + " ").replace( rclass, " " );
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- className = className.replace(" " + classNames[ c ] + " ", " ");
- }
- elem.className = jQuery.trim( className );
-
- } else {
- elem.className = "";
- }
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- state = stateVal,
- classNames = value.split( rspace );
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space seperated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- } else if ( type === "undefined" || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
- }
-
- // toggle whole className
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
- }
- });
- },
-
- hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
- return true;
- }
- }
-
- return false;
- },
-
- val: function( value ) {
- var hooks, ret, isFunction,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var self = jQuery(this), val;
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map(val, function ( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
- }
- },
- select: {
- get: function( elem ) {
- var value, i, max, option,
- index = elem.selectedIndex,
- values = [],
- options = elem.options,
- one = elem.type === "select-one";
-
- // Nothing was selected
- if ( index < 0 ) {
- return null;
- }
-
- // Loop through all the selected options
- i = one ? index : 0;
- max = one ? index + 1 : options.length;
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // Don't return options that are disabled or in a disabled optgroup
- if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
- (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
- if ( one && !values.length && options.length ) {
- return jQuery( options[ index ] ).val();
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- attrFn: {
- val: true,
- css: true,
- html: true,
- text: true,
- data: true,
- width: true,
- height: true,
- offset: true
- },
-
- attr: function( elem, name, value, pass ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- if ( pass && name in jQuery.attrFn ) {
- return jQuery( elem )[ name ]( value );
- }
-
- // Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === "undefined" ) {
- return jQuery.prop( elem, name, value );
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( notxml ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
- return;
-
- } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, "" + value );
- return value;
- }
-
- } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
-
- ret = elem.getAttribute( name );
-
- // Non-existent attributes return null, we normalize to undefined
- return ret === null ?
- undefined :
- ret;
- }
- },
-
- removeAttr: function( elem, value ) {
- var propName, attrNames, name, l, isBool,
- i = 0;
-
- if ( value && elem.nodeType === 1 ) {
- attrNames = value.toLowerCase().split( rspace );
- l = attrNames.length;
-
- for ( ; i < l; i++ ) {
- name = attrNames[ i ];
-
- if ( name ) {
- propName = jQuery.propFix[ name ] || name;
- isBool = rboolean.test( name );
-
- // See #9699 for explanation of this approach (setting first, then removal)
- // Do not do this for boolean attributes (see #10870)
- if ( !isBool ) {
- jQuery.attr( elem, name, "" );
- }
- elem.removeAttribute( getSetAttribute ? name : propName );
-
- // Set corresponding property to false for boolean attributes
- if ( isBool && propName in elem ) {
- elem[ propName ] = false;
- }
- }
- }
- }
- },
-
- attrHooks: {
- type: {
- set: function( elem, value ) {
- // We can't allow the type property to be changed (since it causes problems in IE)
- if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
- jQuery.error( "type property can't be changed" );
- } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to it's default in case type is set after value
- // This is for element creation
- var val = elem.value;
- elem.setAttribute( "type", value );
- if ( val ) {
- elem.value = val;
- }
- return value;
- }
- }
- },
- // Use the value property for back compat
- // Use the nodeHook for button elements in IE6/7 (#1954)
- value: {
- get: function( elem, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.get( elem, name );
- }
- return name in elem ?
- elem.value :
- null;
- },
- set: function( elem, value, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.set( elem, value, name );
- }
- // Does not return so that setAttribute is also used
- elem.value = value;
- }
- }
- },
-
- propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
- prop: function( elem, name, value ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- if ( notxml ) {
- // Fix name and attach hooks
- name = jQuery.propFix[ name ] || name;
- hooks = jQuery.propHooks[ name ];
- }
-
- if ( value !== undefined ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return ( elem[ name ] = value );
- }
-
- } else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return elem[ name ];
- }
- }
- },
-
- propHooks: {
- tabIndex: {
- get: function( elem ) {
- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- undefined;
- }
- }
- }
-});
-
-// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
-jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
-
-// Hook for boolean attributes
-boolHook = {
- get: function( elem, name ) {
- // Align boolean attributes with corresponding properties
- // Fall back to attribute presence where some booleans are not supported
- var attrNode,
- property = jQuery.prop( elem, name );
- return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
- name.toLowerCase() :
- undefined;
- },
- set: function( elem, value, name ) {
- var propName;
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else {
- // value is true since we know at this point it's type boolean and not false
- // Set boolean attributes to the same name and set the DOM property
- propName = jQuery.propFix[ name ] || name;
- if ( propName in elem ) {
- // Only set the IDL specifically if it already exists on the element
- elem[ propName ] = true;
- }
-
- elem.setAttribute( name, name.toLowerCase() );
- }
- return name;
- }
-};
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
- fixSpecified = {
- name: true,
- id: true,
- coords: true
- };
-
- // Use this for any attribute in IE6/7
- // This fixes almost every IE6/7 issue
- nodeHook = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret;
- ret = elem.getAttributeNode( name );
- return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
- ret.nodeValue :
- undefined;
- },
- set: function( elem, value, name ) {
- // Set the existing or create a new attribute node
- var ret = elem.getAttributeNode( name );
- if ( !ret ) {
- ret = document.createAttribute( name );
- elem.setAttributeNode( ret );
- }
- return ( ret.nodeValue = value + "" );
- }
- };
-
- // Apply the nodeHook to tabindex
- jQuery.attrHooks.tabindex.set = nodeHook.set;
-
- // Set width and height to auto instead of 0 on empty string( Bug #8150 )
- // This is for removals
- jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- });
- });
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- get: nodeHook.get,
- set: function( elem, value, name ) {
- if ( value === "" ) {
- value = "false";
- }
- nodeHook.set( elem, value, name );
- }
- };
-}
-
-
-// Some attributes require a special call on IE
-if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret === null ? undefined : ret;
- }
- });
- });
-}
-
-if ( !jQuery.support.style ) {
- jQuery.attrHooks.style = {
- get: function( elem ) {
- // Return undefined in the case of empty string
- // Normalize to lowercase since IE uppercases css property names
- return elem.style.cssText.toLowerCase() || undefined;
- },
- set: function( elem, value ) {
- return ( elem.style.cssText = "" + value );
- }
- };
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
- get: function( elem ) {
- var parent = elem.parentNode;
-
- if ( parent ) {
- parent.selectedIndex;
-
- // Make sure that it also works with optgroups, see #5701
- if ( parent.parentNode ) {
- parent.parentNode.selectedIndex;
- }
- }
- return null;
- }
- });
-}
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
-}
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
-});
-
-
-
-
-var rformElems = /^(?:textarea|input|select)$/i,
- rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
- rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
- quickParse = function( selector ) {
- var quick = rquickIs.exec( selector );
- if ( quick ) {
- // 0 1 2 3
- // [ _, tag, id, class ]
- quick[1] = ( quick[1] || "" ).toLowerCase();
- quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
- }
- return quick;
- },
- quickIs = function( elem, m ) {
- var attrs = elem.attributes || {};
- return (
- (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
- (!m[2] || (attrs.id || {}).value === m[2]) &&
- (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
- );
- },
- hoverHack = function( events ) {
- return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
- };
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
- add: function( elem, types, handler, data, selector ) {
-
- var elemData, eventHandle, events,
- t, tns, type, namespaces, handleObj,
- handleObjIn, quick, handlers, special;
-
- // Don't attach events to noData or text/comment nodes (allow plain objects tho)
- if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
- return;
- }
-
- // Caller can pass in an object of custom data in lieu of the handler
- if ( handler.handler ) {
- handleObjIn = handler;
- handler = handleObjIn.handler;
- selector = handleObjIn.selector;
- }
-
- // Make sure that the handler has a unique ID, used to find/remove it later
- if ( !handler.guid ) {
- handler.guid = jQuery.guid++;
- }
-
- // Init the element's event structure and main handler, if this is the first
- events = elemData.events;
- if ( !events ) {
- elemData.events = events = {};
- }
- eventHandle = elemData.handle;
- if ( !eventHandle ) {
- elemData.handle = eventHandle = function( e ) {
- // Discard the second event of a jQuery.event.trigger() and
- // when an event is called after a page has unloaded
- return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
- undefined;
- };
- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
- eventHandle.elem = elem;
- }
-
- // Handle multiple events separated by a space
- // jQuery(...).bind("mouseover mouseout", fn);
- types = jQuery.trim( hoverHack(types) ).split( " " );
- for ( t = 0; t < types.length; t++ ) {
-
- tns = rtypenamespace.exec( types[t] ) || [];
- type = tns[1];
- namespaces = ( tns[2] || "" ).split( "." ).sort();
-
- // If event changes its type, use the special event handlers for the changed type
- special = jQuery.event.special[ type ] || {};
-
- // If selector defined, determine special event api type, otherwise given type
- type = ( selector ? special.delegateType : special.bindType ) || type;
-
- // Update special based on newly reset type
- special = jQuery.event.special[ type ] || {};
-
- // handleObj is passed to all event handlers
- handleObj = jQuery.extend({
- type: type,
- origType: tns[1],
- data: data,
- handler: handler,
- guid: handler.guid,
- selector: selector,
- quick: selector && quickParse( selector ),
- namespace: namespaces.join(".")
- }, handleObjIn );
-
- // Init the event handler queue if we're the first
- handlers = events[ type ];
- if ( !handlers ) {
- handlers = events[ type ] = [];
- handlers.delegateCount = 0;
-
- // Only use addEventListener/attachEvent if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- // Bind the global event handler to the element
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
-
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, eventHandle );
- }
- }
- }
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
-
- if ( !handleObj.handler.guid ) {
- handleObj.handler.guid = handler.guid;
- }
- }
-
- // Add to the element's handler list, delegates in front
- if ( selector ) {
- handlers.splice( handlers.delegateCount++, 0, handleObj );
- } else {
- handlers.push( handleObj );
- }
-
- // Keep track of which events have ever been used, for event optimization
- jQuery.event.global[ type ] = true;
- }
-
- // Nullify elem to prevent memory leaks in IE
- elem = null;
- },
-
- global: {},
-
- // Detach an event or set of events from an element
- remove: function( elem, types, handler, selector, mappedTypes ) {
-
- var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
- t, tns, type, origType, namespaces, origCount,
- j, events, special, handle, eventType, handleObj;
-
- if ( !elemData || !(events = elemData.events) ) {
- return;
- }
-
- // Once for each type.namespace in types; type may be omitted
- types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
- for ( t = 0; t < types.length; t++ ) {
- tns = rtypenamespace.exec( types[t] ) || [];
- type = origType = tns[1];
- namespaces = tns[2];
-
- // Unbind all events (on this namespace, if provided) for the element
- if ( !type ) {
- for ( type in events ) {
- jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
- }
- continue;
- }
-
- special = jQuery.event.special[ type ] || {};
- type = ( selector? special.delegateType : special.bindType ) || type;
- eventType = events[ type ] || [];
- origCount = eventType.length;
- namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
-
- // Remove matching events
- for ( j = 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( ( mappedTypes || origType === handleObj.origType ) &&
- ( !handler || handler.guid === handleObj.guid ) &&
- ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
- eventType.splice( j--, 1 );
-
- if ( handleObj.selector ) {
- eventType.delegateCount--;
- }
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
- }
- }
-
- // Remove generic event handler if we removed something and no more handlers exist
- // (avoids potential for endless recursion during removal of special event handlers)
- if ( eventType.length === 0 && origCount !== eventType.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
- jQuery.removeEvent( elem, type, elemData.handle );
- }
-
- delete events[ type ];
- }
- }
-
- // Remove the expando if it's no longer used
- if ( jQuery.isEmptyObject( events ) ) {
- handle = elemData.handle;
- if ( handle ) {
- handle.elem = null;
- }
-
- // removeData also checks for emptiness and clears the expando if empty
- // so use it instead of delete
- jQuery.removeData( elem, [ "events", "handle" ], true );
- }
- },
-
- // Events that are safe to short-circuit if no handlers are attached.
- // Native DOM events should not be added, they may have inline handlers.
- customEvent: {
- "getData": true,
- "setData": true,
- "changeData": true
- },
-
- trigger: function( event, data, elem, onlyHandlers ) {
- // Don't do events on text and comment nodes
- if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
- return;
- }
-
- // Event object or event type
- var type = event.type || event,
- namespaces = [],
- cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf( "!" ) >= 0 ) {
- // Exclusive events trigger only for the exact event (no namespaces)
- type = type.slice(0, -1);
- exclusive = true;
- }
-
- if ( type.indexOf( "." ) >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
-
- if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
- // No jQuery handlers for this event type, and it can't have inline handlers
- return;
- }
-
- // Caller can pass in an Event, Object, or just an event type string
- event = typeof event === "object" ?
- // jQuery.Event object
- event[ jQuery.expando ] ? event :
- // Object literal
- new jQuery.Event( type, event ) :
- // Just the event type (string)
- new jQuery.Event( type );
-
- event.type = type;
- event.isTrigger = true;
- event.exclusive = exclusive;
- event.namespace = namespaces.join( "." );
- event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
- ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
-
- // Handle a global trigger
- if ( !elem ) {
-
- // TODO: Stop taunting the data cache; remove global events and always attach to document
- cache = jQuery.cache;
- for ( i in cache ) {
- if ( cache[ i ].events && cache[ i ].events[ type ] ) {
- jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
- }
- }
- return;
- }
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data != null ? jQuery.makeArray( data ) : [];
- data.unshift( event );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- eventPath = [[ elem, special.bindType || type ]];
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
- old = null;
- for ( ; cur; cur = cur.parentNode ) {
- eventPath.push([ cur, bubbleType ]);
- old = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( old && old === elem.ownerDocument ) {
- eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
- }
- }
-
- // Fire handlers on the event path
- for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
-
- cur = eventPath[i][0];
- event.type = eventPath[i][1];
-
- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
- // Note that this is a bare JS function and not a jQuery handler
- handle = ontype && cur[ ontype ];
- if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
- event.preventDefault();
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction() check here because IE6/7 fails that test.
- // Don't do default actions on window, that's where global variables be (#6170)
- // IE<9 dies on focus/blur to hidden element (#1486)
- if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- old = elem[ ontype ];
-
- if ( old ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- elem[ type ]();
- jQuery.event.triggered = undefined;
-
- if ( old ) {
- elem[ ontype ] = old;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
-
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event || window.event );
-
- var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
- delegateCount = handlers.delegateCount,
- args = [].slice.call( arguments, 0 ),
- run_all = !event.exclusive && !event.namespace,
- special = jQuery.event.special[ event.type ] || {},
- handlerQueue = [],
- i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
-
- // Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
- event.delegateTarget = this;
-
- // Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
- return;
- }
-
- // Determine handlers that should run if there are delegated events
- // Avoid non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && !(event.button && event.type === "click") ) {
-
- // Pregenerate a single jQuery object for reuse with .is()
- jqcur = jQuery(this);
- jqcur.context = this.ownerDocument || this;
-
- for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
-
- // Don't process events on disabled elements (#6911, #8165)
- if ( cur.disabled !== true ) {
- selMatch = {};
- matches = [];
- jqcur[0] = cur;
- for ( i = 0; i < delegateCount; i++ ) {
- handleObj = handlers[ i ];
- sel = handleObj.selector;
-
- if ( selMatch[ sel ] === undefined ) {
- selMatch[ sel ] = (
- handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
- );
- }
- if ( selMatch[ sel ] ) {
- matches.push( handleObj );
- }
- }
- if ( matches.length ) {
- handlerQueue.push({ elem: cur, matches: matches });
- }
- }
- }
- }
-
- // Add the remaining (directly-bound) handlers
- if ( handlers.length > delegateCount ) {
- handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
- }
-
- // Run delegates first; they may want to stop propagation beneath us
- for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
- matched = handlerQueue[ i ];
- event.currentTarget = matched.elem;
-
- for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
- handleObj = matched.matches[ j ];
-
- // Triggered event must either 1) be non-exclusive and have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
-
- event.data = handleObj.data;
- event.handleObj = handleObj;
-
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
-
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- // Call the postDispatch hook for the mapped type
- if ( special.postDispatch ) {
- special.postDispatch.call( this, event );
- }
-
- return event.result;
- },
-
- // Includes some event props shared by KeyEvent and MouseEvent
- // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
- props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
- fixHooks: {},
-
- keyHooks: {
- props: "char charCode key keyCode".split(" "),
- filter: function( event, original ) {
-
- // Add which for key events
- if ( event.which == null ) {
- event.which = original.charCode != null ? original.charCode : original.keyCode;
- }
-
- return event;
- }
- },
-
- mouseHooks: {
- props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
- filter: function( event, original ) {
- var eventDoc, doc, body,
- button = original.button,
- fromElement = original.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && original.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.body;
-
- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
- }
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && fromElement ) {
- event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
- }
-
- return event;
- }
- },
-
- fix: function( event ) {
- if ( event[ jQuery.expando ] ) {
- return event;
- }
-
- // Create a writable copy of the event object and normalize some properties
- var i, prop,
- originalEvent = event,
- fixHook = jQuery.event.fixHooks[ event.type ] || {},
- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
- event = jQuery.Event( originalEvent );
-
- for ( i = copy.length; i; ) {
- prop = copy[ --i ];
- event[ prop ] = originalEvent[ prop ];
- }
-
- // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
- if ( !event.target ) {
- event.target = originalEvent.srcElement || document;
- }
-
- // Target should not be a text node (#504, Safari)
- if ( event.target.nodeType === 3 ) {
- event.target = event.target.parentNode;
- }
-
- // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
- if ( event.metaKey === undefined ) {
- event.metaKey = event.ctrlKey;
- }
-
- return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
- },
-
- special: {
- ready: {
- // Make sure the ready event is setup
- setup: jQuery.bindReady
- },
-
- load: {
- // Prevent triggered image.load events from bubbling to window.load
- noBubble: true
- },
-
- focus: {
- delegateType: "focusin"
- },
- blur: {
- delegateType: "focusout"
- },
-
- beforeunload: {
- setup: function( data, namespaces, eventHandle ) {
- // We only want to do this special case on windows
- if ( jQuery.isWindow( this ) ) {
- this.onbeforeunload = eventHandle;
- }
- },
-
- teardown: function( namespaces, eventHandle ) {
- if ( this.onbeforeunload === eventHandle ) {
- this.onbeforeunload = null;
- }
- }
- }
- },
-
- simulate: function( type, elem, event, bubble ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- var e = jQuery.extend(
- new jQuery.Event(),
- event,
- { type: type,
- isSimulated: true,
- originalEvent: {}
- }
- );
- if ( bubble ) {
- jQuery.event.trigger( e, null, elem );
- } else {
- jQuery.event.dispatch.call( elem, e );
- }
- if ( e.isDefaultPrevented() ) {
- event.preventDefault();
- }
- }
-};
-
-// Some plugins are using, but it's undocumented/deprecated and will be removed.
-// The 1.7 special event interface should provide all the hooks needed now.
-jQuery.event.handle = jQuery.event.dispatch;
-
-jQuery.removeEvent = document.removeEventListener ?
- function( elem, type, handle ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, handle, false );
- }
- } :
- function( elem, type, handle ) {
- if ( elem.detachEvent ) {
- elem.detachEvent( "on" + type, handle );
- }
- };
-
-jQuery.Event = function( src, props ) {
- // Allow instantiation without the 'new' keyword
- if ( !(this instanceof jQuery.Event) ) {
- return new jQuery.Event( src, props );
- }
-
- // Event object
- if ( src && src.type ) {
- this.originalEvent = src;
- this.type = src.type;
-
- // Events bubbling up the document may have been marked as prevented
- // by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
-
- // Event type
- } else {
- this.type = src;
- }
-
- // Put explicitly provided properties onto the event object
- if ( props ) {
- jQuery.extend( this, props );
- }
-
- // Create a timestamp if incoming event doesn't have one
- this.timeStamp = src && src.timeStamp || jQuery.now();
-
- // Mark it as fixed
- this[ jQuery.expando ] = true;
-};
-
-function returnFalse() {
- return false;
-}
-function returnTrue() {
- return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
- preventDefault: function() {
- this.isDefaultPrevented = returnTrue;
-
- var e = this.originalEvent;
- if ( !e ) {
- return;
- }
-
- // if preventDefault exists run it on the original event
- if ( e.preventDefault ) {
- e.preventDefault();
-
- // otherwise set the returnValue property of the original event to false (IE)
- } else {
- e.returnValue = false;
- }
- },
- stopPropagation: function() {
- this.isPropagationStopped = returnTrue;
-
- var e = this.originalEvent;
- if ( !e ) {
- return;
- }
- // if stopPropagation exists run it on the original event
- if ( e.stopPropagation ) {
- e.stopPropagation();
- }
- // otherwise set the cancelBubble property of the original event to true (IE)
- e.cancelBubble = true;
- },
- stopImmediatePropagation: function() {
- this.isImmediatePropagationStopped = returnTrue;
- this.stopPropagation();
- },
- isDefaultPrevented: returnFalse,
- isPropagationStopped: returnFalse,
- isImmediatePropagationStopped: returnFalse
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-}, function( orig, fix ) {
- jQuery.event.special[ orig ] = {
- delegateType: fix,
- bindType: fix,
-
- handle: function( event ) {
- var target = this,
- related = event.relatedTarget,
- handleObj = event.handleObj,
- selector = handleObj.selector,
- ret;
-
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
- event.type = handleObj.origType;
- ret = handleObj.handler.apply( this, arguments );
- event.type = fix;
- }
- return ret;
- }
- };
-});
-
-// IE submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
- jQuery.event.special.submit = {
- setup: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Lazy-add a submit handler when a descendant form may potentially be submitted
- jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
- // Node name check avoids a VML-related crash in IE (#9807)
- var elem = e.target,
- form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
- if ( form && !form._submit_attached ) {
- jQuery.event.add( form, "submit._submit", function( event ) {
- event._submit_bubble = true;
- });
- form._submit_attached = true;
- }
- });
- // return undefined since we don't need an event listener
- },
-
- postDispatch: function( event ) {
- // If form was submitted by the user, bubble the event up the tree
- if ( event._submit_bubble ) {
- delete event._submit_bubble;
- if ( this.parentNode && !event.isTrigger ) {
- jQuery.event.simulate( "submit", this.parentNode, event, true );
- }
- }
- },
-
- teardown: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
- jQuery.event.remove( this, "._submit" );
- }
- };
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !jQuery.support.changeBubbles ) {
-
- jQuery.event.special.change = {
-
- setup: function() {
-
- if ( rformElems.test( this.nodeName ) ) {
- // IE doesn't fire change on a check/radio until blur; trigger it on click
- // after a propertychange. Eat the blur-change in special.change.handle.
- // This still fires onchange a second time for check/radio after blur.
- if ( this.type === "checkbox" || this.type === "radio" ) {
- jQuery.event.add( this, "propertychange._change", function( event ) {
- if ( event.originalEvent.propertyName === "checked" ) {
- this._just_changed = true;
- }
- });
- jQuery.event.add( this, "click._change", function( event ) {
- if ( this._just_changed && !event.isTrigger ) {
- this._just_changed = false;
- jQuery.event.simulate( "change", this, event, true );
- }
- });
- }
- return false;
- }
- // Delegated event; lazy-add a change handler on descendant inputs
- jQuery.event.add( this, "beforeactivate._change", function( e ) {
- var elem = e.target;
-
- if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
- jQuery.event.add( elem, "change._change", function( event ) {
- if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
- jQuery.event.simulate( "change", this.parentNode, event, true );
- }
- });
- elem._change_attached = true;
- }
- });
- },
-
- handle: function( event ) {
- var elem = event.target;
-
- // Swallow native change events from checkbox/radio, we already triggered them above
- if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
- return event.handleObj.handler.apply( this, arguments );
- }
- },
-
- teardown: function() {
- jQuery.event.remove( this, "._change" );
-
- return rformElems.test( this.nodeName );
- }
- };
-}
-
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
-}
-
-jQuery.fn.extend({
-
- on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
- var origFn, type;
-
- // Types can be a map of types/handlers
- if ( typeof types === "object" ) {
- // ( types-Object, selector, data )
- if ( typeof selector !== "string" ) { // && selector != null
- // ( types-Object, data )
- data = data || selector;
- selector = undefined;
- }
- for ( type in types ) {
- this.on( type, selector, data, types[ type ], one );
- }
- return this;
- }
-
- if ( data == null && fn == null ) {
- // ( types, fn )
- fn = selector;
- data = selector = undefined;
- } else if ( fn == null ) {
- if ( typeof selector === "string" ) {
- // ( types, selector, fn )
- fn = data;
- data = undefined;
- } else {
- // ( types, data, fn )
- fn = data;
- data = selector;
- selector = undefined;
- }
- }
- if ( fn === false ) {
- fn = returnFalse;
- } else if ( !fn ) {
- return this;
- }
-
- if ( one === 1 ) {
- origFn = fn;
- fn = function( event ) {
- // Can use an empty set, since event contains the info
- jQuery().off( event );
- return origFn.apply( this, arguments );
- };
- // Use same guid so caller can remove using origFn
- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
- }
- return this.each( function() {
- jQuery.event.add( this, types, fn, data, selector );
- });
- },
- one: function( types, selector, data, fn ) {
- return this.on( types, selector, data, fn, 1 );
- },
- off: function( types, selector, fn ) {
- if ( types && types.preventDefault && types.handleObj ) {
- // ( event ) dispatched jQuery.Event
- var handleObj = types.handleObj;
- jQuery( types.delegateTarget ).off(
- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
- handleObj.selector,
- handleObj.handler
- );
- return this;
- }
- if ( typeof types === "object" ) {
- // ( types-object [, selector] )
- for ( var type in types ) {
- this.off( type, selector, types[ type ] );
- }
- return this;
- }
- if ( selector === false || typeof selector === "function" ) {
- // ( types [, fn] )
- fn = selector;
- selector = undefined;
- }
- if ( fn === false ) {
- fn = returnFalse;
- }
- return this.each(function() {
- jQuery.event.remove( this, types, fn, selector );
- });
- },
-
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
-
- live: function( types, data, fn ) {
- jQuery( this.context ).on( types, this.selector, data, fn );
- return this;
- },
- die: function( types, fn ) {
- jQuery( this.context ).off( types, this.selector || "**", fn );
- return this;
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- // ( namespace ) or ( selector, types [, fn] )
- return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
- },
-
- trigger: function( type, data ) {
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- },
- triggerHandler: function( type, data ) {
- if ( this[0] ) {
- return jQuery.event.trigger( type, data, this[0], true );
- }
- },
-
- toggle: function( fn ) {
- // Save reference to arguments for access in closure
- var args = arguments,
- guid = fn.guid || jQuery.guid++,
- i = 0,
- toggler = function( event ) {
- // Figure out which function to execute
- var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
- // Make sure that clicks stop
- event.preventDefault();
-
- // and execute the function
- return args[ lastToggle ].apply( this, arguments ) || false;
- };
-
- // link all the functions, so any of them can unbind this click handler
- toggler.guid = guid;
- while ( i < args.length ) {
- args[ i++ ].guid = guid;
- }
-
- return this.click( toggler );
- },
-
- hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- }
-});
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.on( name, null, data, fn ) :
- this.trigger( name );
- };
-
- if ( jQuery.attrFn ) {
- jQuery.attrFn[ name ] = true;
- }
-
- if ( rkeyEvent.test( name ) ) {
- jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
- }
-
- if ( rmouseEvent.test( name ) ) {
- jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
- }
-});
-
-
-
-/*!
- * Sizzle CSS Selector Engine
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- * More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
- expando = "sizcache" + (Math.random() + '').replace('.', ''),
- done = 0,
- toString = Object.prototype.toString,
- hasDuplicate = false,
- baseHasDuplicate = true,
- rBackslash = /\\/g,
- rReturn = /\r\n/g,
- rNonWord = /\W/;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-// Thus far that includes Google Chrome.
-[0, 0].sort(function() {
- baseHasDuplicate = false;
- return 0;
-});
-
-var Sizzle = function( selector, context, results, seed ) {
- results = results || [];
- context = context || document;
-
- var origContext = context;
-
- if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
- return [];
- }
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- var m, set, checkSet, extra, ret, cur, pop, i,
- prune = true,
- contextXML = Sizzle.isXML( context ),
- parts = [],
- soFar = selector;
-
- // Reset the position of the chunker regexp (start from head)
- do {
- chunker.exec( "" );
- m = chunker.exec( soFar );
-
- if ( m ) {
- soFar = m[3];
-
- parts.push( m[1] );
-
- if ( m[2] ) {
- extra = m[3];
- break;
- }
- }
- } while ( m );
-
- if ( parts.length > 1 && origPOS.exec( selector ) ) {
-
- if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
- set = posProcess( parts[0] + parts[1], context, seed );
-
- } else {
- set = Expr.relative[ parts[0] ] ?
- [ context ] :
- Sizzle( parts.shift(), context );
-
- while ( parts.length ) {
- selector = parts.shift();
-
- if ( Expr.relative[ selector ] ) {
- selector += parts.shift();
- }
-
- set = posProcess( selector, set, seed );
- }
- }
-
- } else {
- // Take a shortcut and set the context if the root selector is an ID
- // (but not if it'll be faster if the inner selector is an ID)
- if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
- Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-
- ret = Sizzle.find( parts.shift(), context, contextXML );
- context = ret.expr ?
- Sizzle.filter( ret.expr, ret.set )[0] :
- ret.set[0];
- }
-
- if ( context ) {
- ret = seed ?
- { expr: parts.pop(), set: makeArray(seed) } :
- Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-
- set = ret.expr ?
- Sizzle.filter( ret.expr, ret.set ) :
- ret.set;
-
- if ( parts.length > 0 ) {
- checkSet = makeArray( set );
-
- } else {
- prune = false;
- }
-
- while ( parts.length ) {
- cur = parts.pop();
- pop = cur;
-
- if ( !Expr.relative[ cur ] ) {
- cur = "";
- } else {
- pop = parts.pop();
- }
-
- if ( pop == null ) {
- pop = context;
- }
-
- Expr.relative[ cur ]( checkSet, pop, contextXML );
- }
-
- } else {
- checkSet = parts = [];
- }
- }
-
- if ( !checkSet ) {
- checkSet = set;
- }
-
- if ( !checkSet ) {
- Sizzle.error( cur || selector );
- }
-
- if ( toString.call(checkSet) === "[object Array]" ) {
- if ( !prune ) {
- results.push.apply( results, checkSet );
-
- } else if ( context && context.nodeType === 1 ) {
- for ( i = 0; checkSet[i] != null; i++ ) {
- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
- results.push( set[i] );
- }
- }
-
- } else {
- for ( i = 0; checkSet[i] != null; i++ ) {
- if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
- results.push( set[i] );
- }
- }
- }
-
- } else {
- makeArray( checkSet, results );
- }
-
- if ( extra ) {
- Sizzle( extra, origContext, results, seed );
- Sizzle.uniqueSort( results );
- }
-
- return results;
-};
-
-Sizzle.uniqueSort = function( results ) {
- if ( sortOrder ) {
- hasDuplicate = baseHasDuplicate;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( var i = 1; i < results.length; i++ ) {
- if ( results[i] === results[ i - 1 ] ) {
- results.splice( i--, 1 );
- }
- }
- }
- }
-
- return results;
-};
-
-Sizzle.matches = function( expr, set ) {
- return Sizzle( expr, null, null, set );
-};
-
-Sizzle.matchesSelector = function( node, expr ) {
- return Sizzle( expr, null, null, [node] ).length > 0;
-};
-
-Sizzle.find = function( expr, context, isXML ) {
- var set, i, len, match, type, left;
-
- if ( !expr ) {
- return [];
- }
-
- for ( i = 0, len = Expr.order.length; i < len; i++ ) {
- type = Expr.order[i];
-
- if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
- left = match[1];
- match.splice( 1, 1 );
-
- if ( left.substr( left.length - 1 ) !== "\\" ) {
- match[1] = (match[1] || "").replace( rBackslash, "" );
- set = Expr.find[ type ]( match, context, isXML );
-
- if ( set != null ) {
- expr = expr.replace( Expr.match[ type ], "" );
- break;
- }
- }
- }
- }
-
- if ( !set ) {
- set = typeof context.getElementsByTagName !== "undefined" ?
- context.getElementsByTagName( "*" ) :
- [];
- }
-
- return { set: set, expr: expr };
-};
-
-Sizzle.filter = function( expr, set, inplace, not ) {
- var match, anyFound,
- type, found, item, filter, left,
- i, pass,
- old = expr,
- result = [],
- curLoop = set,
- isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
-
- while ( expr && set.length ) {
- for ( type in Expr.filter ) {
- if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
- filter = Expr.filter[ type ];
- left = match[1];
-
- anyFound = false;
-
- match.splice(1,1);
-
- if ( left.substr( left.length - 1 ) === "\\" ) {
- continue;
- }
-
- if ( curLoop === result ) {
- result = [];
- }
-
- if ( Expr.preFilter[ type ] ) {
- match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
- if ( !match ) {
- anyFound = found = true;
-
- } else if ( match === true ) {
- continue;
- }
- }
-
- if ( match ) {
- for ( i = 0; (item = curLoop[i]) != null; i++ ) {
- if ( item ) {
- found = filter( item, match, i, curLoop );
- pass = not ^ found;
-
- if ( inplace && found != null ) {
- if ( pass ) {
- anyFound = true;
-
- } else {
- curLoop[i] = false;
- }
-
- } else if ( pass ) {
- result.push( item );
- anyFound = true;
- }
- }
- }
- }
-
- if ( found !== undefined ) {
- if ( !inplace ) {
- curLoop = result;
- }
-
- expr = expr.replace( Expr.match[ type ], "" );
-
- if ( !anyFound ) {
- return [];
- }
-
- break;
- }
- }
- }
-
- // Improper expression
- if ( expr === old ) {
- if ( anyFound == null ) {
- Sizzle.error( expr );
-
- } else {
- break;
- }
- }
-
- old = expr;
- }
-
- return curLoop;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-/**
- * Utility function for retreiving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-var getText = Sizzle.getText = function( elem ) {
- var i, node,
- nodeType = elem.nodeType,
- ret = "";
-
- if ( nodeType ) {
- if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent || innerText for elements
- if ( typeof elem.textContent === 'string' ) {
- return elem.textContent;
- } else if ( typeof elem.innerText === 'string' ) {
- // Replace IE's carriage returns
- return elem.innerText.replace( rReturn, '' );
- } else {
- // Traverse it's children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- } else {
-
- // If no nodeType, this is expected to be an array
- for ( i = 0; (node = elem[i]); i++ ) {
- // Do not traverse comment nodes
- if ( node.nodeType !== 8 ) {
- ret += getText( node );
- }
- }
- }
- return ret;
-};
-
-var Expr = Sizzle.selectors = {
- order: [ "ID", "NAME", "TAG" ],
-
- match: {
- ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
- CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
- TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
- CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
- PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
- },
-
- leftMatch: {},
-
- attrMap: {
- "class": "className",
- "for": "htmlFor"
- },
-
- attrHandle: {
- href: function( elem ) {
- return elem.getAttribute( "href" );
- },
- type: function( elem ) {
- return elem.getAttribute( "type" );
- }
- },
-
- relative: {
- "+": function(checkSet, part){
- var isPartStr = typeof part === "string",
- isTag = isPartStr && !rNonWord.test( part ),
- isPartStrNotTag = isPartStr && !isTag;
-
- if ( isTag ) {
- part = part.toLowerCase();
- }
-
- for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
- if ( (elem = checkSet[i]) ) {
- while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
- checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
- elem || false :
- elem === part;
- }
- }
-
- if ( isPartStrNotTag ) {
- Sizzle.filter( part, checkSet, true );
- }
- },
-
- ">": function( checkSet, part ) {
- var elem,
- isPartStr = typeof part === "string",
- i = 0,
- l = checkSet.length;
-
- if ( isPartStr && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
-
- for ( ; i < l; i++ ) {
- elem = checkSet[i];
-
- if ( elem ) {
- var parent = elem.parentNode;
- checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
- }
- }
-
- } else {
- for ( ; i < l; i++ ) {
- elem = checkSet[i];
-
- if ( elem ) {
- checkSet[i] = isPartStr ?
- elem.parentNode :
- elem.parentNode === part;
- }
- }
-
- if ( isPartStr ) {
- Sizzle.filter( part, checkSet, true );
- }
- }
- },
-
- "": function(checkSet, part, isXML){
- var nodeCheck,
- doneName = done++,
- checkFn = dirCheck;
-
- if ( typeof part === "string" && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
- nodeCheck = part;
- checkFn = dirNodeCheck;
- }
-
- checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
- },
-
- "~": function( checkSet, part, isXML ) {
- var nodeCheck,
- doneName = done++,
- checkFn = dirCheck;
-
- if ( typeof part === "string" && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
- nodeCheck = part;
- checkFn = dirNodeCheck;
- }
-
- checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
- }
- },
-
- find: {
- ID: function( match, context, isXML ) {
- if ( typeof context.getElementById !== "undefined" && !isXML ) {
- var m = context.getElementById(match[1]);
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- },
-
- NAME: function( match, context ) {
- if ( typeof context.getElementsByName !== "undefined" ) {
- var ret = [],
- results = context.getElementsByName( match[1] );
-
- for ( var i = 0, l = results.length; i < l; i++ ) {
- if ( results[i].getAttribute("name") === match[1] ) {
- ret.push( results[i] );
- }
- }
-
- return ret.length === 0 ? null : ret;
- }
- },
-
- TAG: function( match, context ) {
- if ( typeof context.getElementsByTagName !== "undefined" ) {
- return context.getElementsByTagName( match[1] );
- }
- }
- },
- preFilter: {
- CLASS: function( match, curLoop, inplace, result, not, isXML ) {
- match = " " + match[1].replace( rBackslash, "" ) + " ";
-
- if ( isXML ) {
- return match;
- }
-
- for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
- if ( elem ) {
- if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
- if ( !inplace ) {
- result.push( elem );
- }
-
- } else if ( inplace ) {
- curLoop[i] = false;
- }
- }
- }
-
- return false;
- },
-
- ID: function( match ) {
- return match[1].replace( rBackslash, "" );
- },
-
- TAG: function( match, curLoop ) {
- return match[1].replace( rBackslash, "" ).toLowerCase();
- },
-
- CHILD: function( match ) {
- if ( match[1] === "nth" ) {
- if ( !match[2] ) {
- Sizzle.error( match[0] );
- }
-
- match[2] = match[2].replace(/^\+|\s*/g, '');
-
- // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
- var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
- match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
- !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
- // calculate the numbers (first)n+(last) including if they are negative
- match[2] = (test[1] + (test[2] || 1)) - 0;
- match[3] = test[3] - 0;
- }
- else if ( match[2] ) {
- Sizzle.error( match[0] );
- }
-
- // TODO: Move to normal caching system
- match[0] = done++;
-
- return match;
- },
-
- ATTR: function( match, curLoop, inplace, result, not, isXML ) {
- var name = match[1] = match[1].replace( rBackslash, "" );
-
- if ( !isXML && Expr.attrMap[name] ) {
- match[1] = Expr.attrMap[name];
- }
-
- // Handle if an un-quoted value was used
- match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
-
- if ( match[2] === "~=" ) {
- match[4] = " " + match[4] + " ";
- }
-
- return match;
- },
-
- PSEUDO: function( match, curLoop, inplace, result, not ) {
- if ( match[1] === "not" ) {
- // If we're dealing with a complex expression, or a simple one
- if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
- match[3] = Sizzle(match[3], null, null, curLoop);
-
- } else {
- var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-
- if ( !inplace ) {
- result.push.apply( result, ret );
- }
-
- return false;
- }
-
- } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
- return true;
- }
-
- return match;
- },
-
- POS: function( match ) {
- match.unshift( true );
-
- return match;
- }
- },
-
- filters: {
- enabled: function( elem ) {
- return elem.disabled === false && elem.type !== "hidden";
- },
-
- disabled: function( elem ) {
- return elem.disabled === true;
- },
-
- checked: function( elem ) {
- return elem.checked === true;
- },
-
- selected: function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- parent: function( elem ) {
- return !!elem.firstChild;
- },
-
- empty: function( elem ) {
- return !elem.firstChild;
- },
-
- has: function( elem, i, match ) {
- return !!Sizzle( match[3], elem ).length;
- },
-
- header: function( elem ) {
- return (/h\d/i).test( elem.nodeName );
- },
-
- text: function( elem ) {
- var attr = elem.getAttribute( "type" ), type = elem.type;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
- },
-
- radio: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
- },
-
- checkbox: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
- },
-
- file: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
- },
-
- password: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
- },
-
- submit: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && "submit" === elem.type;
- },
-
- image: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
- },
-
- reset: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && "reset" === elem.type;
- },
-
- button: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && "button" === elem.type || name === "button";
- },
-
- input: function( elem ) {
- return (/input|select|textarea|button/i).test( elem.nodeName );
- },
-
- focus: function( elem ) {
- return elem === elem.ownerDocument.activeElement;
- }
- },
- setFilters: {
- first: function( elem, i ) {
- return i === 0;
- },
-
- last: function( elem, i, match, array ) {
- return i === array.length - 1;
- },
-
- even: function( elem, i ) {
- return i % 2 === 0;
- },
-
- odd: function( elem, i ) {
- return i % 2 === 1;
- },
-
- lt: function( elem, i, match ) {
- return i < match[3] - 0;
- },
-
- gt: function( elem, i, match ) {
- return i > match[3] - 0;
- },
-
- nth: function( elem, i, match ) {
- return match[3] - 0 === i;
- },
-
- eq: function( elem, i, match ) {
- return match[3] - 0 === i;
- }
- },
- filter: {
- PSEUDO: function( elem, match, i, array ) {
- var name = match[1],
- filter = Expr.filters[ name ];
-
- if ( filter ) {
- return filter( elem, i, match, array );
-
- } else if ( name === "contains" ) {
- return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
-
- } else if ( name === "not" ) {
- var not = match[3];
-
- for ( var j = 0, l = not.length; j < l; j++ ) {
- if ( not[j] === elem ) {
- return false;
- }
- }
-
- return true;
-
- } else {
- Sizzle.error( name );
- }
- },
-
- CHILD: function( elem, match ) {
- var first, last,
- doneName, parent, cache,
- count, diff,
- type = match[1],
- node = elem;
-
- switch ( type ) {
- case "only":
- case "first":
- while ( (node = node.previousSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- if ( type === "first" ) {
- return true;
- }
-
- node = elem;
-
- /* falls through */
- case "last":
- while ( (node = node.nextSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- return true;
-
- case "nth":
- first = match[2];
- last = match[3];
-
- if ( first === 1 && last === 0 ) {
- return true;
- }
-
- doneName = match[0];
- parent = elem.parentNode;
-
- if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
- count = 0;
-
- for ( node = parent.firstChild; node; node = node.nextSibling ) {
- if ( node.nodeType === 1 ) {
- node.nodeIndex = ++count;
- }
- }
-
- parent[ expando ] = doneName;
- }
-
- diff = elem.nodeIndex - last;
-
- if ( first === 0 ) {
- return diff === 0;
-
- } else {
- return ( diff % first === 0 && diff / first >= 0 );
- }
- }
- },
-
- ID: function( elem, match ) {
- return elem.nodeType === 1 && elem.getAttribute("id") === match;
- },
-
- TAG: function( elem, match ) {
- return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
- },
-
- CLASS: function( elem, match ) {
- return (" " + (elem.className || elem.getAttribute("class")) + " ")
- .indexOf( match ) > -1;
- },
-
- ATTR: function( elem, match ) {
- var name = match[1],
- result = Sizzle.attr ?
- Sizzle.attr( elem, name ) :
- Expr.attrHandle[ name ] ?
- Expr.attrHandle[ name ]( elem ) :
- elem[ name ] != null ?
- elem[ name ] :
- elem.getAttribute( name ),
- value = result + "",
- type = match[2],
- check = match[4];
-
- return result == null ?
- type === "!=" :
- !type && Sizzle.attr ?
- result != null :
- type === "=" ?
- value === check :
- type === "*=" ?
- value.indexOf(check) >= 0 :
- type === "~=" ?
- (" " + value + " ").indexOf(check) >= 0 :
- !check ?
- value && result !== false :
- type === "!=" ?
- value !== check :
- type === "^=" ?
- value.indexOf(check) === 0 :
- type === "$=" ?
- value.substr(value.length - check.length) === check :
- type === "|=" ?
- value === check || value.substr(0, check.length + 1) === check + "-" :
- false;
- },
-
- POS: function( elem, match, i, array ) {
- var name = match[2],
- filter = Expr.setFilters[ name ];
-
- if ( filter ) {
- return filter( elem, i, match, array );
- }
- }
- }
-};
-
-var origPOS = Expr.match.POS,
- fescape = function(all, num){
- return "\\" + (num - 0 + 1);
- };
-
-for ( var type in Expr.match ) {
- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
- Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
-}
-// Expose origPOS
-// "global" as in regardless of relation to brackets/parens
-Expr.match.globalPOS = origPOS;
-
-var makeArray = function( array, results ) {
- array = Array.prototype.slice.call( array, 0 );
-
- if ( results ) {
- results.push.apply( results, array );
- return results;
- }
-
- return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
- Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch( e ) {
- makeArray = function( array, results ) {
- var i = 0,
- ret = results || [];
-
- if ( toString.call(array) === "[object Array]" ) {
- Array.prototype.push.apply( ret, array );
-
- } else {
- if ( typeof array.length === "number" ) {
- for ( var l = array.length; i < l; i++ ) {
- ret.push( array[i] );
- }
-
- } else {
- for ( ; array[i]; i++ ) {
- ret.push( array[i] );
- }
- }
- }
-
- return ret;
- };
-}
-
-var sortOrder, siblingCheck;
-
-if ( document.documentElement.compareDocumentPosition ) {
- sortOrder = function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
- return a.compareDocumentPosition ? -1 : 1;
- }
-
- return a.compareDocumentPosition(b) & 4 ? -1 : 1;
- };
-
-} else {
- sortOrder = function( a, b ) {
- // The nodes are identical, we can exit early
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Fallback to using sourceIndex (in IE) if it's available on both nodes
- } else if ( a.sourceIndex && b.sourceIndex ) {
- return a.sourceIndex - b.sourceIndex;
- }
-
- var al, bl,
- ap = [],
- bp = [],
- aup = a.parentNode,
- bup = b.parentNode,
- cur = aup;
-
- // If the nodes are siblings (or identical) we can do a quick check
- if ( aup === bup ) {
- return siblingCheck( a, b );
-
- // If no parents were found then the nodes are disconnected
- } else if ( !aup ) {
- return -1;
-
- } else if ( !bup ) {
- return 1;
- }
-
- // Otherwise they're somewhere else in the tree so we need
- // to build up a full list of the parentNodes for comparison
- while ( cur ) {
- ap.unshift( cur );
- cur = cur.parentNode;
- }
-
- cur = bup;
-
- while ( cur ) {
- bp.unshift( cur );
- cur = cur.parentNode;
- }
-
- al = ap.length;
- bl = bp.length;
-
- // Start walking down the tree looking for a discrepancy
- for ( var i = 0; i < al && i < bl; i++ ) {
- if ( ap[i] !== bp[i] ) {
- return siblingCheck( ap[i], bp[i] );
- }
- }
-
- // We ended someplace up the tree so do a sibling check
- return i === al ?
- siblingCheck( a, bp[i], -1 ) :
- siblingCheck( ap[i], b, 1 );
- };
-
- siblingCheck = function( a, b, ret ) {
- if ( a === b ) {
- return ret;
- }
-
- var cur = a.nextSibling;
-
- while ( cur ) {
- if ( cur === b ) {
- return -1;
- }
-
- cur = cur.nextSibling;
- }
-
- return 1;
- };
-}
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
- // We're going to inject a fake input element with a specified name
- var form = document.createElement("div"),
- id = "script" + (new Date()).getTime(),
- root = document.documentElement;
-
- form.innerHTML = " ";
-
- // Inject it into the root element, check its status, and remove it quickly
- root.insertBefore( form, root.firstChild );
-
- // The workaround has to do additional checks after a getElementById
- // Which slows things down for other browsers (hence the branching)
- if ( document.getElementById( id ) ) {
- Expr.find.ID = function( match, context, isXML ) {
- if ( typeof context.getElementById !== "undefined" && !isXML ) {
- var m = context.getElementById(match[1]);
-
- return m ?
- m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
- [m] :
- undefined :
- [];
- }
- };
-
- Expr.filter.ID = function( elem, match ) {
- var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-
- return elem.nodeType === 1 && node && node.nodeValue === match;
- };
- }
-
- root.removeChild( form );
-
- // release memory in IE
- root = form = null;
-})();
-
-(function(){
- // Check to see if the browser returns only elements
- // when doing getElementsByTagName("*")
-
- // Create a fake element
- var div = document.createElement("div");
- div.appendChild( document.createComment("") );
-
- // Make sure no comments are found
- if ( div.getElementsByTagName("*").length > 0 ) {
- Expr.find.TAG = function( match, context ) {
- var results = context.getElementsByTagName( match[1] );
-
- // Filter out possible comments
- if ( match[1] === "*" ) {
- var tmp = [];
-
- for ( var i = 0; results[i]; i++ ) {
- if ( results[i].nodeType === 1 ) {
- tmp.push( results[i] );
- }
- }
-
- results = tmp;
- }
-
- return results;
- };
- }
-
- // Check to see if an attribute returns normalized href attributes
- div.innerHTML = " ";
-
- if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
- div.firstChild.getAttribute("href") !== "#" ) {
-
- Expr.attrHandle.href = function( elem ) {
- return elem.getAttribute( "href", 2 );
- };
- }
-
- // release memory in IE
- div = null;
-})();
-
-if ( document.querySelectorAll ) {
- (function(){
- var oldSizzle = Sizzle,
- div = document.createElement("div"),
- id = "__sizzle__";
-
- div.innerHTML = "
";
-
- // Safari can't handle uppercase or unicode characters when
- // in quirks mode.
- if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
- return;
- }
-
- Sizzle = function( query, context, extra, seed ) {
- context = context || document;
-
- // Only use querySelectorAll on non-XML documents
- // (ID selectors don't work in non-HTML documents)
- if ( !seed && !Sizzle.isXML(context) ) {
- // See if we find a selector to speed up
- var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-
- if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
- // Speed-up: Sizzle("TAG")
- if ( match[1] ) {
- return makeArray( context.getElementsByTagName( query ), extra );
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
- return makeArray( context.getElementsByClassName( match[2] ), extra );
- }
- }
-
- if ( context.nodeType === 9 ) {
- // Speed-up: Sizzle("body")
- // The body element only exists once, optimize finding it
- if ( query === "body" && context.body ) {
- return makeArray( [ context.body ], extra );
-
- // Speed-up: Sizzle("#ID")
- } else if ( match && match[3] ) {
- var elem = context.getElementById( match[3] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id === match[3] ) {
- return makeArray( [ elem ], extra );
- }
-
- } else {
- return makeArray( [], extra );
- }
- }
-
- try {
- return makeArray( context.querySelectorAll(query), extra );
- } catch(qsaError) {}
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- var oldContext = context,
- old = context.getAttribute( "id" ),
- nid = old || id,
- hasParent = context.parentNode,
- relativeHierarchySelector = /^\s*[+~]/.test( query );
-
- if ( !old ) {
- context.setAttribute( "id", nid );
- } else {
- nid = nid.replace( /'/g, "\\$&" );
- }
- if ( relativeHierarchySelector && hasParent ) {
- context = context.parentNode;
- }
-
- try {
- if ( !relativeHierarchySelector || hasParent ) {
- return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
- }
-
- } catch(pseudoError) {
- } finally {
- if ( !old ) {
- oldContext.removeAttribute( "id" );
- }
- }
- }
- }
-
- return oldSizzle(query, context, extra, seed);
- };
-
- for ( var prop in oldSizzle ) {
- Sizzle[ prop ] = oldSizzle[ prop ];
- }
-
- // release memory in IE
- div = null;
- })();
-}
-
-(function(){
- var html = document.documentElement,
- matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
-
- if ( matches ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9 fails this)
- var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
- pseudoWorks = false;
-
- try {
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( document.documentElement, "[test!='']:sizzle" );
-
- } catch( pseudoError ) {
- pseudoWorks = true;
- }
-
- Sizzle.matchesSelector = function( node, expr ) {
- // Make sure that attribute selectors are quoted
- expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
-
- if ( !Sizzle.isXML( node ) ) {
- try {
- if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
- var ret = matches.call( node, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || !disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9, so check for that
- node.document && node.document.nodeType !== 11 ) {
- return ret;
- }
- }
- } catch(e) {}
- }
-
- return Sizzle(expr, null, null, [node]).length > 0;
- };
- }
-})();
-
-(function(){
- var div = document.createElement("div");
-
- div.innerHTML = "
";
-
- // Opera can't find a second classname (in 9.6)
- // Also, make sure that getElementsByClassName actually exists
- if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
- return;
- }
-
- // Safari caches class attributes, doesn't catch changes (in 3.2)
- div.lastChild.className = "e";
-
- if ( div.getElementsByClassName("e").length === 1 ) {
- return;
- }
-
- Expr.order.splice(1, 0, "CLASS");
- Expr.find.CLASS = function( match, context, isXML ) {
- if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
- return context.getElementsByClassName(match[1]);
- }
- };
-
- // release memory in IE
- div = null;
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
-
- if ( elem ) {
- var match = false;
-
- elem = elem[dir];
-
- while ( elem ) {
- if ( elem[ expando ] === doneName ) {
- match = checkSet[elem.sizset];
- break;
- }
-
- if ( elem.nodeType === 1 && !isXML ){
- elem[ expando ] = doneName;
- elem.sizset = i;
- }
-
- if ( elem.nodeName.toLowerCase() === cur ) {
- match = elem;
- break;
- }
-
- elem = elem[dir];
- }
-
- checkSet[i] = match;
- }
- }
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
-
- if ( elem ) {
- var match = false;
-
- elem = elem[dir];
-
- while ( elem ) {
- if ( elem[ expando ] === doneName ) {
- match = checkSet[elem.sizset];
- break;
- }
-
- if ( elem.nodeType === 1 ) {
- if ( !isXML ) {
- elem[ expando ] = doneName;
- elem.sizset = i;
- }
-
- if ( typeof cur !== "string" ) {
- if ( elem === cur ) {
- match = true;
- break;
- }
-
- } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
- match = elem;
- break;
- }
- }
-
- elem = elem[dir];
- }
-
- checkSet[i] = match;
- }
- }
-}
-
-if ( document.documentElement.contains ) {
- Sizzle.contains = function( a, b ) {
- return a !== b && (a.contains ? a.contains(b) : true);
- };
-
-} else if ( document.documentElement.compareDocumentPosition ) {
- Sizzle.contains = function( a, b ) {
- return !!(a.compareDocumentPosition(b) & 16);
- };
-
-} else {
- Sizzle.contains = function() {
- return false;
- };
-}
-
-Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function( selector, context, seed ) {
- var match,
- tmpSet = [],
- later = "",
- root = context.nodeType ? [context] : context;
-
- // Position selectors must be done after the filter
- // And so must :not(positional) so we move all PSEUDOs to the end
- while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
- later += match[0];
- selector = selector.replace( Expr.match.PSEUDO, "" );
- }
-
- selector = Expr.relative[selector] ? selector + "*" : selector;
-
- for ( var i = 0, l = root.length; i < l; i++ ) {
- Sizzle( selector, root[i], tmpSet, seed );
- }
-
- return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
-Sizzle.selectors.attrMap = {};
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})();
-
-
-var runtil = /Until$/,
- rparentsprev = /^(?:parents|prevUntil|prevAll)/,
- // Note: This RegExp should be improved, or likely pulled from Sizzle
- rmultiselector = /,/,
- isSimple = /^.[^:#\[\.,]*$/,
- slice = Array.prototype.slice,
- POS = jQuery.expr.match.globalPOS,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
-jQuery.fn.extend({
- find: function( selector ) {
- var self = this,
- i, l;
-
- if ( typeof selector !== "string" ) {
- return jQuery( selector ).filter(function() {
- for ( i = 0, l = self.length; i < l; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- });
- }
-
- var ret = this.pushStack( "", "find", selector ),
- length, n, r;
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- length = ret.length;
- jQuery.find( selector, this[i], ret );
-
- if ( i > 0 ) {
- // Make sure that the results are unique
- for ( n = length; n < ret.length; n++ ) {
- for ( r = 0; r < length; r++ ) {
- if ( ret[r] === ret[n] ) {
- ret.splice(n--, 1);
- break;
- }
- }
- }
- }
- }
-
- return ret;
- },
-
- has: function( target ) {
- var targets = jQuery( target );
- return this.filter(function() {
- for ( var i = 0, l = targets.length; i < l; i++ ) {
- if ( jQuery.contains( this, targets[i] ) ) {
- return true;
- }
- }
- });
- },
-
- not: function( selector ) {
- return this.pushStack( winnow(this, selector, false), "not", selector);
- },
-
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true), "filter", selector );
- },
-
- is: function( selector ) {
- return !!selector && (
- typeof selector === "string" ?
- // If this is a positional selector, check membership in the returned set
- // so $("p:first").is("p:last") won't return true for a doc with two "p".
- POS.test( selector ) ?
- jQuery( selector, this.context ).index( this[0] ) >= 0 :
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
- },
-
- closest: function( selectors, context ) {
- var ret = [], i, l, cur = this[0];
-
- // Array (deprecated as of jQuery 1.7)
- if ( jQuery.isArray( selectors ) ) {
- var level = 1;
-
- while ( cur && cur.ownerDocument && cur !== context ) {
- for ( i = 0; i < selectors.length; i++ ) {
-
- if ( jQuery( cur ).is( selectors[ i ] ) ) {
- ret.push({ selector: selectors[ i ], elem: cur, level: level });
- }
- }
-
- cur = cur.parentNode;
- level++;
- }
-
- return ret;
- }
-
- // String
- var pos = POS.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- cur = this[i];
-
- while ( cur ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
- break;
-
- } else {
- cur = cur.parentNode;
- if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
- break;
- }
- }
- }
- }
-
- ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
-
- return this.pushStack( ret, "closest", selectors );
- },
-
- // Determine the position of an element within
- // the matched set of elements
- index: function( elem ) {
-
- // No argument, return index in parent
- if ( !elem ) {
- return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
- }
-
- // index in selector
- if ( typeof elem === "string" ) {
- return jQuery.inArray( this[0], jQuery( elem ) );
- }
-
- // Locate the position of the desired element
- return jQuery.inArray(
- // If it receives a jQuery object, the first element is used
- elem.jquery ? elem[0] : elem, this );
- },
-
- add: function( selector, context ) {
- var set = typeof selector === "string" ?
- jQuery( selector, context ) :
- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
- all = jQuery.merge( this.get(), set );
-
- return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
- all :
- jQuery.unique( all ) );
- },
-
- andSelf: function() {
- return this.add( this.prevObject );
- }
-});
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
- return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-jQuery.each({
- parent: function( elem ) {
- var parent = elem.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
- },
- parents: function( elem ) {
- return jQuery.dir( elem, "parentNode" );
- },
- parentsUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "parentNode", until );
- },
- next: function( elem ) {
- return jQuery.nth( elem, 2, "nextSibling" );
- },
- prev: function( elem ) {
- return jQuery.nth( elem, 2, "previousSibling" );
- },
- nextAll: function( elem ) {
- return jQuery.dir( elem, "nextSibling" );
- },
- prevAll: function( elem ) {
- return jQuery.dir( elem, "previousSibling" );
- },
- nextUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "nextSibling", until );
- },
- prevUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "previousSibling", until );
- },
- siblings: function( elem ) {
- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
- },
- children: function( elem ) {
- return jQuery.sibling( elem.firstChild );
- },
- contents: function( elem ) {
- return jQuery.nodeName( elem, "iframe" ) ?
- elem.contentDocument || elem.contentWindow.document :
- jQuery.makeArray( elem.childNodes );
- }
-}, function( name, fn ) {
- jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until );
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, slice.call( arguments ).join(",") );
- };
-});
-
-jQuery.extend({
- filter: function( expr, elems, not ) {
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
- },
-
- dir: function( elem, dir, until ) {
- var matched = [],
- cur = elem[ dir ];
-
- while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
- if ( cur.nodeType === 1 ) {
- matched.push( cur );
- }
- cur = cur[dir];
- }
- return matched;
- },
-
- nth: function( cur, result, dir, elem ) {
- result = result || 1;
- var num = 0;
-
- for ( ; cur; cur = cur[dir] ) {
- if ( cur.nodeType === 1 && ++num === result ) {
- break;
- }
- }
-
- return cur;
- },
-
- sibling: function( n, elem ) {
- var r = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType === 1 && n !== elem ) {
- r.push( n );
- }
- }
-
- return r;
- }
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem, i ) {
- return ( elem === qualifier ) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem, i ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
- });
-}
-
-
-
-
-function createSafeFragment( document ) {
- var list = nodeNames.split( "|" ),
- safeFrag = document.createDocumentFragment();
-
- if ( safeFrag.createElement ) {
- while ( list.length ) {
- safeFrag.createElement(
- list.pop()
- );
- }
- }
- return safeFrag;
-}
-
-var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
- "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
- rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
- rleadingWhitespace = /^\s+/,
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
- rtagName = /<([\w:]+)/,
- rtbody = / ]", "i"),
- // checked="checked" or checked
- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /\/(java|ecma)script/i,
- rcleanScript = /^\s*", "" ],
- legend: [ 1, "", " " ],
- thead: [ 1, "" ],
- tr: [ 2, "" ],
- td: [ 3, "" ],
- col: [ 2, "" ],
- area: [ 1, "", " " ],
- _default: [ 0, "", "" ]
- },
- safeFragment = createSafeFragment( document );
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE can't serialize and
-
-
-
- it('should auto compile', function() {
- expect(element('div[compile]').text()).toBe('Hello Angular');
- input('html').enter('{{name}}!');
- expect(element('div[compile]').text()).toBe('Angular!');
- });
-
-
-
- *
- *
- * @param {string|DOMElement} element Element or HTML string to compile into a template function.
- * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
- * @param {number} maxPriority only apply directives lower then given priority (Only effects the
- * root element(s), not their children)
- * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
- * (a DOM element/tree) to a scope. Where:
- *
- * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
- * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
- * `template` and call the `cloneAttachFn` function allowing the caller to attach the
- * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
- * called as: `cloneAttachFn(clonedElement, scope)` where:
- *
- * * `clonedElement` - is a clone of the original `element` passed into the compiler.
- * * `scope` - is the current scope with which the linking function is working with.
- *
- * Calling the linking function returns the element of the template. It is either the original element
- * passed in, or the clone of the element if the `cloneAttachFn` is provided.
- *
- * After linking the view is not updated until after a call to $digest which typically is done by
- * Angular automatically.
- *
- * If you need access to the bound view, there are two ways to do it:
- *
- * - If you are not asking the linking function to clone the template, create the DOM element(s)
- * before you send them to the compiler and keep this reference around.
- *
- * var element = $compile('{{total}}
')(scope);
- *
- *
- * - if on the other hand, you need the element to be cloned, the view reference from the original
- * example would not point to the clone, but rather to the original template that was cloned. In
- * this case, you can access the clone via the cloneAttachFn:
- *
- * var templateHTML = angular.element('{{total}}
'),
- * scope = ....;
- *
- * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
- * //attach the clone to DOM document at the right place
- * });
- *
- * //now we have reference to the cloned DOM via `clone`
- *
- *
- *
- * For information on how the compiler works, see the
- * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
- */
-
-
-/**
- * @ngdoc service
- * @name ng.$compileProvider
- * @function
- *
- * @description
- */
-$CompileProvider.$inject = ['$provide'];
-function $CompileProvider($provide) {
- var hasDirectives = {},
- Suffix = 'Directive',
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
- MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
- urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
-
-
- /**
- * @ngdoc function
- * @name ng.$compileProvider#directive
- * @methodOf ng.$compileProvider
- * @function
- *
- * @description
- * Register a new directives with the compiler.
- *
- * @param {string} name Name of the directive in camel-case. (ie ngBind which will match as
- * ng-bind).
- * @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
- * info.
- * @returns {ng.$compileProvider} Self for chaining.
- */
- this.directive = function registerDirective(name, directiveFactory) {
- if (isString(name)) {
- assertArg(directiveFactory, 'directive');
- if (!hasDirectives.hasOwnProperty(name)) {
- hasDirectives[name] = [];
- $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
- function($injector, $exceptionHandler) {
- var directives = [];
- forEach(hasDirectives[name], function(directiveFactory) {
- try {
- var directive = $injector.invoke(directiveFactory);
- if (isFunction(directive)) {
- directive = { compile: valueFn(directive) };
- } else if (!directive.compile && directive.link) {
- directive.compile = valueFn(directive.link);
- }
- directive.priority = directive.priority || 0;
- directive.name = directive.name || name;
- directive.require = directive.require || (directive.controller && directive.name);
- directive.restrict = directive.restrict || 'A';
- directives.push(directive);
- } catch (e) {
- $exceptionHandler(e);
- }
- });
- return directives;
- }]);
- }
- hasDirectives[name].push(directiveFactory);
- } else {
- forEach(name, reverseParams(registerDirective));
- }
- return this;
- };
-
-
- /**
- * @ngdoc function
- * @name ng.$compileProvider#urlSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
- *
- * @description
- * Retrieves or overrides the default regular expression that is used for whitelisting of safe
- * urls during a[href] sanitization.
- *
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
- *
- * Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
- * absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
- * expression. If a match is found the original url is written into the dom. Otherwise the
- * absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
- *
- * @param {RegExp=} regexp New regexp to whitelist urls with.
- * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
- * chaining otherwise.
- */
- this.urlSanitizationWhitelist = function(regexp) {
- if (isDefined(regexp)) {
- urlSanitizationWhitelist = regexp;
- return this;
- }
- return urlSanitizationWhitelist;
- };
-
-
- this.$get = [
- '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope', '$document',
- function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope, $document) {
-
- var Attributes = function(element, attr) {
- this.$$element = element;
- this.$attr = attr || {};
- };
-
- Attributes.prototype = {
- $normalize: directiveNormalize,
-
-
- /**
- * Set a normalized attribute on the element in a way such that all directives
- * can share the attribute. This function properly handles boolean attributes.
- * @param {string} key Normalized key. (ie ngAttribute)
- * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
- * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
- * Defaults to true.
- * @param {string=} attrName Optional none normalized name. Defaults to key.
- */
- $set: function(key, value, writeAttr, attrName) {
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- $$observers = this.$$observers,
- normalizedVal;
-
- if (booleanKey) {
- this.$$element.prop(key, value);
- attrName = booleanKey;
- }
-
- this[key] = value;
-
- // translate normalized key to actual key
- if (attrName) {
- this.$attr[key] = attrName;
- } else {
- attrName = this.$attr[key];
- if (!attrName) {
- this.$attr[key] = attrName = snake_case(key, '-');
- }
- }
-
-
- // sanitize a[href] values
- if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
- urlSanitizationNode.setAttribute('href', value);
-
- // href property always returns normalized absolute url, so we can match against that
- normalizedVal = urlSanitizationNode.href;
- if (!normalizedVal.match(urlSanitizationWhitelist)) {
- this[key] = value = 'unsafe:' + normalizedVal;
- }
- }
-
-
- if (writeAttr !== false) {
- if (value === null || value === undefined) {
- this.$$element.removeAttr(attrName);
- } else {
- this.$$element.attr(attrName, value);
- }
- }
-
- // fire observers
- $$observers && forEach($$observers[key], function(fn) {
- try {
- fn(value);
- } catch (e) {
- $exceptionHandler(e);
- }
- });
- },
-
-
- /**
- * Observe an interpolated attribute.
- * The observer will never be called, if given attribute is not interpolated.
- *
- * @param {string} key Normalized key. (ie ngAttribute) .
- * @param {function(*)} fn Function that will be called whenever the attribute value changes.
- * @returns {function(*)} the `fn` Function passed in.
- */
- $observe: function(key, fn) {
- var attrs = this,
- $$observers = (attrs.$$observers || (attrs.$$observers = {})),
- listeners = ($$observers[key] || ($$observers[key] = []));
-
- listeners.push(fn);
- $rootScope.$evalAsync(function() {
- if (!listeners.$$inter) {
- // no one registered attribute interpolation function, so lets call it manually
- fn(attrs[key]);
- }
- });
- return fn;
- }
- };
-
- var urlSanitizationNode = $document[0].createElement('a'),
- startSymbol = $interpolate.startSymbol(),
- endSymbol = $interpolate.endSymbol(),
- denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
- ? identity
- : function denormalizeTemplate(template) {
- return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
- };
-
-
- return compile;
-
- //================================
-
- function compile($compileNodes, transcludeFn, maxPriority) {
- if (!($compileNodes instanceof jqLite)) {
- // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
- $compileNodes = jqLite($compileNodes);
- }
- // We can not compile top level text elements since text nodes can be merged and we will
- // not be able to attach scope data to them, so we will wrap them in
- forEach($compileNodes, function(node, index){
- if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
- $compileNodes[index] = jqLite(node).wrap(' ').parent()[0];
- }
- });
- var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
- return function publicLinkFn(scope, cloneConnectFn){
- assertArg(scope, 'scope');
- // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
- // and sometimes changes the structure of the DOM.
- var $linkNode = cloneConnectFn
- ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
- : $compileNodes;
-
- // Attach scope only to non-text nodes.
- for(var i = 0, ii = $linkNode.length; i
- addDirective(directives,
- directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
-
- // iterate over the attributes
- for (var attr, name, nName, value, nAttrs = node.attributes,
- j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
- attr = nAttrs[j];
- if (attr.specified) {
- name = attr.name;
- nName = directiveNormalize(name.toLowerCase());
- attrsMap[nName] = name;
- attrs[nName] = value = trim((msie && name == 'href')
- ? decodeURIComponent(node.getAttribute(name, 2))
- : attr.value);
- if (getBooleanAttrName(node, nName)) {
- attrs[nName] = true; // presence means true
- }
- addAttrInterpolateDirective(node, directives, value, nName);
- addDirective(directives, nName, 'A', maxPriority);
- }
- }
-
- // use class as directive
- className = node.className;
- if (isString(className) && className !== '') {
- while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
- nName = directiveNormalize(match[2]);
- if (addDirective(directives, nName, 'C', maxPriority)) {
- attrs[nName] = trim(match[3]);
- }
- className = className.substr(match.index + match[0].length);
- }
- }
- break;
- case 3: /* Text Node */
- addTextInterpolateDirective(directives, node.nodeValue);
- break;
- case 8: /* Comment */
- try {
- match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
- if (match) {
- nName = directiveNormalize(match[1]);
- if (addDirective(directives, nName, 'M', maxPriority)) {
- attrs[nName] = trim(match[2]);
- }
- }
- } catch (e) {
- // turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
- // Just ignore it and continue. (Can't seem to reproduce in test case.)
- }
- break;
- }
-
- directives.sort(byPriority);
- return directives;
- }
-
-
- /**
- * Once the directives have been collected their compile functions is executed. This method
- * is responsible for inlining directive templates as well as terminating the application
- * of the directives if the terminal directive has been reached..
- *
- * @param {Array} directives Array of collected directives to execute their compile function.
- * this needs to be pre-sorted by priority order.
- * @param {Node} compileNode The raw DOM node to apply the compile functions to
- * @param {Object} templateAttrs The shared attribute function
- * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
- * scope argument is auto-generated to the new child of the transcluded parent scope.
- * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this
- * argument has the root jqLite array so that we can replace widgets on it.
- * @returns linkFn
- */
- function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) {
- var terminalPriority = -Number.MAX_VALUE,
- preLinkFns = [],
- postLinkFns = [],
- newScopeDirective = null,
- newIsolateScopeDirective = null,
- templateDirective = null,
- $compileNode = templateAttrs.$$element = jqLite(compileNode),
- directive,
- directiveName,
- $template,
- transcludeDirective,
- childTranscludeFn = transcludeFn,
- controllerDirectives,
- linkFn,
- directiveValue;
-
- // executes all directives on the current element
- for(var i = 0, ii = directives.length; i < ii; i++) {
- directive = directives[i];
- $template = undefined;
-
- if (terminalPriority > directive.priority) {
- break; // prevent further processing of directives
- }
-
- if (directiveValue = directive.scope) {
- assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
- if (isObject(directiveValue)) {
- safeAddClass($compileNode, 'ng-isolate-scope');
- newIsolateScopeDirective = directive;
- }
- safeAddClass($compileNode, 'ng-scope');
- newScopeDirective = newScopeDirective || directive;
- }
-
- directiveName = directive.name;
-
- if (directiveValue = directive.controller) {
- controllerDirectives = controllerDirectives || {};
- assertNoDuplicate("'" + directiveName + "' controller",
- controllerDirectives[directiveName], directive, $compileNode);
- controllerDirectives[directiveName] = directive;
- }
-
- if (directiveValue = directive.transclude) {
- assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
- transcludeDirective = directive;
- terminalPriority = directive.priority;
- if (directiveValue == 'element') {
- $template = jqLite(compileNode);
- $compileNode = templateAttrs.$$element =
- jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
- compileNode = $compileNode[0];
- replaceWith($rootElement, jqLite($template[0]), compileNode);
- childTranscludeFn = compile($template, transcludeFn, terminalPriority);
- } else {
- $template = jqLite(JQLiteClone(compileNode)).contents();
- $compileNode.html(''); // clear contents
- childTranscludeFn = compile($template, transcludeFn);
- }
- }
-
- if ((directiveValue = directive.template)) {
- assertNoDuplicate('template', templateDirective, directive, $compileNode);
- templateDirective = directive;
- directiveValue = denormalizeTemplate(directiveValue);
-
- if (directive.replace) {
- $template = jqLite('' +
- trim(directiveValue) +
- '
').contents();
- compileNode = $template[0];
-
- if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
- }
-
- replaceWith($rootElement, $compileNode, compileNode);
-
- var newTemplateAttrs = {$attr: {}};
-
- // combine directives from the original node and from the template:
- // - take the array of directives for this element
- // - split it into two parts, those that were already applied and those that weren't
- // - collect directives from the template, add them to the second group and sort them
- // - append the second group with new directives to the first group
- directives = directives.concat(
- collectDirectives(
- compileNode,
- directives.splice(i + 1, directives.length - (i + 1)),
- newTemplateAttrs
- )
- );
- mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
-
- ii = directives.length;
- } else {
- $compileNode.html(directiveValue);
- }
- }
-
- if (directive.templateUrl) {
- assertNoDuplicate('template', templateDirective, directive, $compileNode);
- templateDirective = directive;
- nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
- nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace,
- childTranscludeFn);
- ii = directives.length;
- } else if (directive.compile) {
- try {
- linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
- if (isFunction(linkFn)) {
- addLinkFns(null, linkFn);
- } else if (linkFn) {
- addLinkFns(linkFn.pre, linkFn.post);
- }
- } catch (e) {
- $exceptionHandler(e, startingTag($compileNode));
- }
- }
-
- if (directive.terminal) {
- nodeLinkFn.terminal = true;
- terminalPriority = Math.max(terminalPriority, directive.priority);
- }
-
- }
-
- nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
- nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
-
- // might be normal or delayed nodeLinkFn depending on if templateUrl is present
- return nodeLinkFn;
-
- ////////////////////
-
- function addLinkFns(pre, post) {
- if (pre) {
- pre.require = directive.require;
- preLinkFns.push(pre);
- }
- if (post) {
- post.require = directive.require;
- postLinkFns.push(post);
- }
- }
-
-
- function getControllers(require, $element) {
- var value, retrievalMethod = 'data', optional = false;
- if (isString(require)) {
- while((value = require.charAt(0)) == '^' || value == '?') {
- require = require.substr(1);
- if (value == '^') {
- retrievalMethod = 'inheritedData';
- }
- optional = optional || value == '?';
- }
- value = $element[retrievalMethod]('$' + require + 'Controller');
- if (!value && !optional) {
- throw Error("No controller: " + require);
- }
- return value;
- } else if (isArray(require)) {
- value = [];
- forEach(require, function(require) {
- value.push(getControllers(require, $element));
- });
- }
- return value;
- }
-
-
- function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller;
-
- if (compileNode === linkNode) {
- attrs = templateAttrs;
- } else {
- attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
- }
- $element = attrs.$$element;
-
- if (newIsolateScopeDirective) {
- var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
-
- var parentScope = scope.$parent || scope;
-
- forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
- var match = definiton.match(LOCAL_REGEXP) || [],
- attrName = match[2]|| scopeName,
- mode = match[1], // @, =, or &
- lastValue,
- parentGet, parentSet;
-
- scope.$$isolateBindings[scopeName] = mode + attrName;
-
- switch (mode) {
-
- case '@': {
- attrs.$observe(attrName, function(value) {
- scope[scopeName] = value;
- });
- attrs.$$observers[attrName].$$scope = parentScope;
- break;
- }
-
- case '=': {
- parentGet = $parse(attrs[attrName]);
- parentSet = parentGet.assign || function() {
- // reset the change, or we will throw this exception on every $digest
- lastValue = scope[scopeName] = parentGet(parentScope);
- throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
- ' (directive: ' + newIsolateScopeDirective.name + ')');
- };
- lastValue = scope[scopeName] = parentGet(parentScope);
- scope.$watch(function parentValueWatch() {
- var parentValue = parentGet(parentScope);
-
- if (parentValue !== scope[scopeName]) {
- // we are out of sync and need to copy
- if (parentValue !== lastValue) {
- // parent changed and it has precedence
- lastValue = scope[scopeName] = parentValue;
- } else {
- // if the parent can be assigned then do so
- parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
- }
- }
- return parentValue;
- });
- break;
- }
-
- case '&': {
- parentGet = $parse(attrs[attrName]);
- scope[scopeName] = function(locals) {
- return parentGet(parentScope, locals);
- }
- break;
- }
-
- default: {
- throw Error('Invalid isolate scope definition for directive ' +
- newIsolateScopeDirective.name + ': ' + definiton);
- }
- }
- });
- }
-
- if (controllerDirectives) {
- forEach(controllerDirectives, function(directive) {
- var locals = {
- $scope: scope,
- $element: $element,
- $attrs: attrs,
- $transclude: boundTranscludeFn
- };
-
- controller = directive.controller;
- if (controller == '@') {
- controller = attrs[directive.name];
- }
-
- $element.data(
- '$' + directive.name + 'Controller',
- $controller(controller, locals));
- });
- }
-
- // PRELINKING
- for(i = 0, ii = preLinkFns.length; i < ii; i++) {
- try {
- linkFn = preLinkFns[i];
- linkFn(scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element));
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
- }
-
- // RECURSION
- childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
-
- // POSTLINKING
- for(i = 0, ii = postLinkFns.length; i < ii; i++) {
- try {
- linkFn = postLinkFns[i];
- linkFn(scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element));
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
- }
- }
- }
-
-
- /**
- * looks up the directive and decorates it with exception handling and proper parameters. We
- * call this the boundDirective.
- *
- * @param {string} name name of the directive to look up.
- * @param {string} location The directive must be found in specific format.
- * String containing any of theses characters:
- *
- * * `E`: element name
- * * `A': attribute
- * * `C`: class
- * * `M`: comment
- * @returns true if directive was added.
- */
- function addDirective(tDirectives, name, location, maxPriority) {
- var match = false;
- if (hasDirectives.hasOwnProperty(name)) {
- for(var directive, directives = $injector.get(name + Suffix),
- i = 0, ii = directives.length; i directive.priority) &&
- directive.restrict.indexOf(location) != -1) {
- tDirectives.push(directive);
- match = true;
- }
- } catch(e) { $exceptionHandler(e); }
- }
- }
- return match;
- }
-
-
- /**
- * When the element is replaced with HTML template then the new attributes
- * on the template need to be merged with the existing attributes in the DOM.
- * The desired effect is to have both of the attributes present.
- *
- * @param {object} dst destination attributes (original DOM)
- * @param {object} src source attributes (from the directive template)
- */
- function mergeTemplateAttributes(dst, src) {
- var srcAttr = src.$attr,
- dstAttr = dst.$attr,
- $element = dst.$$element;
-
- // reapply the old attributes to the new element
- forEach(dst, function(value, key) {
- if (key.charAt(0) != '$') {
- if (src[key]) {
- value += (key === 'style' ? ';' : ' ') + src[key];
- }
- dst.$set(key, value, true, srcAttr[key]);
- }
- });
-
- // copy the new attributes on the old attrs object
- forEach(src, function(value, key) {
- if (key == 'class') {
- safeAddClass($element, value);
- dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
- } else if (key == 'style') {
- $element.attr('style', $element.attr('style') + ';' + value);
- } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
- dst[key] = value;
- dstAttr[key] = srcAttr[key];
- }
- });
- }
-
-
- function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs,
- $rootElement, replace, childTranscludeFn) {
- var linkQueue = [],
- afterTemplateNodeLinkFn,
- afterTemplateChildLinkFn,
- beforeTemplateCompileNode = $compileNode[0],
- origAsyncDirective = directives.shift(),
- // The fact that we have to copy and patch the directive seems wrong!
- derivedSyncDirective = extend({}, origAsyncDirective, {
- controller: null, templateUrl: null, transclude: null, scope: null
- });
-
- $compileNode.html('');
-
- $http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
- success(function(content) {
- var compileNode, tempTemplateAttrs, $template;
-
- content = denormalizeTemplate(content);
-
- if (replace) {
- $template = jqLite('' + trim(content) + '
').contents();
- compileNode = $template[0];
-
- if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw new Error(MULTI_ROOT_TEMPLATE_ERROR + content);
- }
-
- tempTemplateAttrs = {$attr: {}};
- replaceWith($rootElement, $compileNode, compileNode);
- collectDirectives(compileNode, directives, tempTemplateAttrs);
- mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
- } else {
- compileNode = beforeTemplateCompileNode;
- $compileNode.html(content);
- }
-
- directives.unshift(derivedSyncDirective);
- afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
- afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
-
-
- while(linkQueue.length) {
- var controller = linkQueue.pop(),
- linkRootElement = linkQueue.pop(),
- beforeTemplateLinkNode = linkQueue.pop(),
- scope = linkQueue.pop(),
- linkNode = compileNode;
-
- if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
- // it was cloned therefore we have to clone as well.
- linkNode = JQLiteClone(compileNode);
- replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
- }
-
- afterTemplateNodeLinkFn(function() {
- beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
- }, scope, linkNode, $rootElement, controller);
- }
- linkQueue = null;
- }).
- error(function(response, code, headers, config) {
- throw Error('Failed to load template: ' + config.url);
- });
-
- return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
- if (linkQueue) {
- linkQueue.push(scope);
- linkQueue.push(node);
- linkQueue.push(rootElement);
- linkQueue.push(controller);
- } else {
- afterTemplateNodeLinkFn(function() {
- beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
- }, scope, node, rootElement, controller);
- }
- };
- }
-
-
- /**
- * Sorting function for bound directives.
- */
- function byPriority(a, b) {
- return b.priority - a.priority;
- }
-
-
- function assertNoDuplicate(what, previousDirective, directive, element) {
- if (previousDirective) {
- throw Error('Multiple directives [' + previousDirective.name + ', ' +
- directive.name + '] asking for ' + what + ' on: ' + startingTag(element));
- }
- }
-
-
- function addTextInterpolateDirective(directives, text) {
- var interpolateFn = $interpolate(text, true);
- if (interpolateFn) {
- directives.push({
- priority: 0,
- compile: valueFn(function textInterpolateLinkFn(scope, node) {
- var parent = node.parent(),
- bindings = parent.data('$binding') || [];
- bindings.push(interpolateFn);
- safeAddClass(parent.data('$binding', bindings), 'ng-binding');
- scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
- node[0].nodeValue = value;
- });
- })
- });
- }
- }
-
-
- function addAttrInterpolateDirective(node, directives, value, name) {
- var interpolateFn = $interpolate(value, true);
-
- // no interpolation found -> ignore
- if (!interpolateFn) return;
-
-
- directives.push({
- priority: 100,
- compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
- var $$observers = (attr.$$observers || (attr.$$observers = {}));
-
- if (name === 'class') {
- // we need to interpolate classes again, in the case the element was replaced
- // and therefore the two class attrs got merged - we want to interpolate the result
- interpolateFn = $interpolate(attr[name], true);
- }
-
- attr[name] = undefined;
- ($$observers[name] || ($$observers[name] = [])).$$inter = true;
- (attr.$$observers && attr.$$observers[name].$$scope || scope).
- $watch(interpolateFn, function interpolateFnWatchAction(value) {
- attr.$set(name, value);
- });
- })
- });
- }
-
-
- /**
- * This is a special jqLite.replaceWith, which can replace items which
- * have no parents, provided that the containing jqLite collection is provided.
- *
- * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
- * in the root of the tree.
- * @param {JqLite} $element The jqLite element which we are going to replace. We keep the shell,
- * but replace its DOM node reference.
- * @param {Node} newNode The new DOM node.
- */
- function replaceWith($rootElement, $element, newNode) {
- var oldNode = $element[0],
- parent = oldNode.parentNode,
- i, ii;
-
- if ($rootElement) {
- for(i = 0, ii = $rootElement.length; i < ii; i++) {
- if ($rootElement[i] == oldNode) {
- $rootElement[i] = newNode;
- break;
- }
- }
- }
-
- if (parent) {
- parent.replaceChild(newNode, oldNode);
- }
-
- newNode[jqLite.expando] = oldNode[jqLite.expando];
- $element[0] = newNode;
- }
- }];
-}
-
-var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
-/**
- * Converts all accepted directives format into proper directive name.
- * All of these will become 'myDirective':
- * my:DiRective
- * my-directive
- * x-my-directive
- * data-my:directive
- *
- * Also there is special case for Moz prefix starting with upper case letter.
- * @param name Name to normalize
- */
-function directiveNormalize(name) {
- return camelCase(name.replace(PREFIX_REGEXP, ''));
-}
-
-/**
- * @ngdoc object
- * @name ng.$compile.directive.Attributes
- * @description
- *
- * A shared object between directive compile / linking functions which contains normalized DOM element
- * attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
- * since all of these are treated as equivalent in Angular:
- *
- *
- */
-
-/**
- * @ngdoc property
- * @name ng.$compile.directive.Attributes#$attr
- * @propertyOf ng.$compile.directive.Attributes
- * @returns {object} A map of DOM element attribute names to the normalized name. This is
- * needed to do reverse lookup from normalized name back to actual name.
- */
-
-
-/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$set
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Set DOM element attribute value.
- *
- *
- * @param {string} name Normalized element attribute name of the property to modify. The name is
- * revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
- * property to the original name.
- * @param {string} value Value to set the attribute to.
- */
-
-
-
-/**
- * Closure compiler type information
- */
-
-function nodesetLinkingFn(
- /* angular.Scope */ scope,
- /* NodeList */ nodeList,
- /* Element */ rootElement,
- /* function(Function) */ boundTranscludeFn
-){}
-
-function directiveLinkingFn(
- /* nodesetLinkingFn */ nodesetLinkingFn,
- /* angular.Scope */ scope,
- /* Node */ node,
- /* Element */ rootElement,
- /* function(Function) */ boundTranscludeFn
-){}
-
-/**
- * @ngdoc object
- * @name ng.$controllerProvider
- * @description
- * The {@link ng.$controller $controller service} is used by Angular to create new
- * controllers.
- *
- * This provider allows controller registration via the
- * {@link ng.$controllerProvider#register register} method.
- */
-function $ControllerProvider() {
- var controllers = {};
-
-
- /**
- * @ngdoc function
- * @name ng.$controllerProvider#register
- * @methodOf ng.$controllerProvider
- * @param {string} name Controller name
- * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
- * annotations in the array notation).
- */
- this.register = function(name, constructor) {
- if (isObject(name)) {
- extend(controllers, name)
- } else {
- controllers[name] = constructor;
- }
- };
-
-
- this.$get = ['$injector', '$window', function($injector, $window) {
-
- /**
- * @ngdoc function
- * @name ng.$controller
- * @requires $injector
- *
- * @param {Function|string} constructor If called with a function then it's considered to be the
- * controller constructor function. Otherwise it's considered to be a string which is used
- * to retrieve the controller constructor using the following steps:
- *
- * * check if a controller with given name is registered via `$controllerProvider`
- * * check if evaluating the string on the current scope returns a constructor
- * * check `window[constructor]` on the global `window` object
- *
- * @param {Object} locals Injection locals for Controller.
- * @return {Object} Instance of given controller.
- *
- * @description
- * `$controller` service is responsible for instantiating controllers.
- *
- * It's just simple call to {@link AUTO.$injector $injector}, but extracted into
- * a service, so that one can override this service with {@link https://gist.github.com/1649788
- * BC version}.
- */
- return function(constructor, locals) {
- if(isString(constructor)) {
- var name = constructor;
- constructor = controllers.hasOwnProperty(name)
- ? controllers[name]
- : getter(locals.$scope, name, true) || getter($window, name, true);
-
- assertArgFn(constructor, name, true);
- }
-
- return $injector.instantiate(constructor, locals);
- };
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$document
- * @requires $window
- *
- * @description
- * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
- * element.
- */
-function $DocumentProvider(){
- this.$get = ['$window', function(window){
- return jqLite(window.document);
- }];
-}
-
-/**
- * @ngdoc function
- * @name ng.$exceptionHandler
- * @requires $log
- *
- * @description
- * Any uncaught exception in angular expressions is delegated to this service.
- * The default implementation simply delegates to `$log.error` which logs it into
- * the browser console.
- *
- * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
- * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
- *
- * @param {Error} exception Exception associated with the error.
- * @param {string=} cause optional information about the context in which
- * the error was thrown.
- *
- */
-function $ExceptionHandlerProvider() {
- this.$get = ['$log', function($log){
- return function(exception, cause) {
- $log.error.apply($log, arguments);
- };
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$interpolateProvider
- * @function
- *
- * @description
- *
- * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
- */
-function $InterpolateProvider() {
- var startSymbol = '{{';
- var endSymbol = '}}';
-
- /**
- * @ngdoc method
- * @name ng.$interpolateProvider#startSymbol
- * @methodOf ng.$interpolateProvider
- * @description
- * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
- *
- * @param {string=} value new value to set the starting symbol to.
- * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
- */
- this.startSymbol = function(value){
- if (value) {
- startSymbol = value;
- return this;
- } else {
- return startSymbol;
- }
- };
-
- /**
- * @ngdoc method
- * @name ng.$interpolateProvider#endSymbol
- * @methodOf ng.$interpolateProvider
- * @description
- * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
- *
- * @param {string=} value new value to set the ending symbol to.
- * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
- */
- this.endSymbol = function(value){
- if (value) {
- endSymbol = value;
- return this;
- } else {
- return endSymbol;
- }
- };
-
-
- this.$get = ['$parse', function($parse) {
- var startSymbolLength = startSymbol.length,
- endSymbolLength = endSymbol.length;
-
- /**
- * @ngdoc function
- * @name ng.$interpolate
- * @function
- *
- * @requires $parse
- *
- * @description
- *
- * Compiles a string with markup into an interpolation function. This service is used by the
- * HTML {@link ng.$compile $compile} service for data binding. See
- * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
- * interpolation markup.
- *
- *
-
- var $interpolate = ...; // injected
- var exp = $interpolate('Hello {{name}}!');
- expect(exp({name:'Angular'}).toEqual('Hello Angular!');
-
- *
- *
- * @param {string} text The text with markup to interpolate.
- * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
- * embedded expression in order to return an interpolation function. Strings with no
- * embedded expression will return null for the interpolation function.
- * @returns {function(context)} an interpolation function which is used to compute the interpolated
- * string. The function has these parameters:
- *
- * * `context`: an object against which any expressions embedded in the strings are evaluated
- * against.
- *
- */
- function $interpolate(text, mustHaveExpression) {
- var startIndex,
- endIndex,
- index = 0,
- parts = [],
- length = text.length,
- hasInterpolation = false,
- fn,
- exp,
- concat = [];
-
- while(index < length) {
- if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
- ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
- (index != startIndex) && parts.push(text.substring(index, startIndex));
- parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
- fn.exp = exp;
- index = endIndex + endSymbolLength;
- hasInterpolation = true;
- } else {
- // we did not find anything, so we have to add the remainder to the parts array
- (index != length) && parts.push(text.substring(index));
- index = length;
- }
- }
-
- if (!(length = parts.length)) {
- // we added, nothing, must have been an empty string.
- parts.push('');
- length = 1;
- }
-
- if (!mustHaveExpression || hasInterpolation) {
- concat.length = length;
- fn = function(context) {
- for(var i = 0, ii = length, part; i html5 url
- } else {
- return composeProtocolHostPort(match.protocol, match.host, match.port) +
- pathPrefixFromBase(basePath) + match.hash.substr(hashPrefix.length);
- }
-}
-
-
-function convertToHashbangUrl(url, basePath, hashPrefix) {
- var match = matchUrl(url);
-
- // already hashbang url
- if (decodeURIComponent(match.path) == basePath) {
- return url;
- // convert html5 url -> hashbang url
- } else {
- var search = match.search && '?' + match.search || '',
- hash = match.hash && '#' + match.hash || '',
- pathPrefix = pathPrefixFromBase(basePath),
- path = match.path.substr(pathPrefix.length);
-
- if (match.path.indexOf(pathPrefix) !== 0) {
- throw Error('Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !');
- }
-
- return composeProtocolHostPort(match.protocol, match.host, match.port) + basePath +
- '#' + hashPrefix + path + search + hash;
- }
-}
-
-
-/**
- * LocationUrl represents an url
- * This object is exposed as $location service when HTML5 mode is enabled and supported
- *
- * @constructor
- * @param {string} url HTML5 url
- * @param {string} pathPrefix
- */
-function LocationUrl(url, pathPrefix, appBaseUrl) {
- pathPrefix = pathPrefix || '';
-
- /**
- * Parse given html5 (regular) url string into properties
- * @param {string} newAbsoluteUrl HTML5 url
- * @private
- */
- this.$$parse = function(newAbsoluteUrl) {
- var match = matchUrl(newAbsoluteUrl, this);
-
- if (match.path.indexOf(pathPrefix) !== 0) {
- throw Error('Invalid url "' + newAbsoluteUrl + '", missing path prefix "' + pathPrefix + '" !');
- }
-
- this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
- this.$$search = parseKeyValue(match.search);
- this.$$hash = match.hash && decodeURIComponent(match.hash) || '';
-
- this.$$compose();
- };
-
- /**
- * Compose url and update `absUrl` property
- * @private
- */
- this.$$compose = function() {
- var search = toKeyValue(this.$$search),
- hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
-
- this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
- this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
- pathPrefix + this.$$url;
- };
-
-
- this.$$rewriteAppUrl = function(absoluteLinkUrl) {
- if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
- return absoluteLinkUrl;
- }
- }
-
-
- this.$$parse(url);
-}
-
-
-/**
- * LocationHashbangUrl represents url
- * This object is exposed as $location service when html5 history api is disabled or not supported
- *
- * @constructor
- * @param {string} url Legacy url
- * @param {string} hashPrefix Prefix for hash part (containing path and search)
- */
-function LocationHashbangUrl(url, hashPrefix, appBaseUrl) {
- var basePath;
-
- /**
- * Parse given hashbang url into properties
- * @param {string} url Hashbang url
- * @private
- */
- this.$$parse = function(url) {
- var match = matchUrl(url, this);
-
-
- if (match.hash && match.hash.indexOf(hashPrefix) !== 0) {
- throw Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '" !');
- }
-
- basePath = match.path + (match.search ? '?' + match.search : '');
- match = HASH_MATCH.exec((match.hash || '').substr(hashPrefix.length));
- if (match[1]) {
- this.$$path = (match[1].charAt(0) == '/' ? '' : '/') + decodeURIComponent(match[1]);
- } else {
- this.$$path = '';
- }
-
- this.$$search = parseKeyValue(match[3]);
- this.$$hash = match[5] && decodeURIComponent(match[5]) || '';
-
- this.$$compose();
- };
-
- /**
- * Compose hashbang url and update `absUrl` property
- * @private
- */
- this.$$compose = function() {
- var search = toKeyValue(this.$$search),
- hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
-
- this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
- this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
- basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
- };
-
- this.$$rewriteAppUrl = function(absoluteLinkUrl) {
- if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
- return absoluteLinkUrl;
- }
- }
-
-
- this.$$parse(url);
-}
-
-
-LocationUrl.prototype = {
-
- /**
- * Has any change been replacing ?
- * @private
- */
- $$replace: false,
-
- /**
- * @ngdoc method
- * @name ng.$location#absUrl
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return full url representation with all segments encoded according to rules specified in
- * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
- *
- * @return {string} full url
- */
- absUrl: locationGetter('$$absUrl'),
-
- /**
- * @ngdoc method
- * @name ng.$location#url
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
- *
- * Change path, search and hash, when called with parameter and return `$location`.
- *
- * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
- * @return {string} url
- */
- url: function(url, replace) {
- if (isUndefined(url))
- return this.$$url;
-
- var match = PATH_MATCH.exec(url);
- if (match[1]) this.path(decodeURIComponent(match[1]));
- if (match[2] || match[1]) this.search(match[3] || '');
- this.hash(match[5] || '', replace);
-
- return this;
- },
-
- /**
- * @ngdoc method
- * @name ng.$location#protocol
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return protocol of current url.
- *
- * @return {string} protocol of current url
- */
- protocol: locationGetter('$$protocol'),
-
- /**
- * @ngdoc method
- * @name ng.$location#host
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return host of current url.
- *
- * @return {string} host of current url.
- */
- host: locationGetter('$$host'),
-
- /**
- * @ngdoc method
- * @name ng.$location#port
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return port of current url.
- *
- * @return {Number} port
- */
- port: locationGetter('$$port'),
-
- /**
- * @ngdoc method
- * @name ng.$location#path
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return path of current url when called without any parameter.
- *
- * Change path when called with parameter and return `$location`.
- *
- * Note: Path should always begin with forward slash (/), this method will add the forward slash
- * if it is missing.
- *
- * @param {string=} path New path
- * @return {string} path
- */
- path: locationGetterSetter('$$path', function(path) {
- return path.charAt(0) == '/' ? path : '/' + path;
- }),
-
- /**
- * @ngdoc method
- * @name ng.$location#search
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return search part (as object) of current url when called without any parameter.
- *
- * Change search part when called with parameter and return `$location`.
- *
- * @param {string|object=} search New search params - string or hash object
- * @param {string=} paramValue If `search` is a string, then `paramValue` will override only a
- * single search parameter. If the value is `null`, the parameter will be deleted.
- *
- * @return {string} search
- */
- search: function(search, paramValue) {
- if (isUndefined(search))
- return this.$$search;
-
- if (isDefined(paramValue)) {
- if (paramValue === null) {
- delete this.$$search[search];
- } else {
- this.$$search[search] = paramValue;
- }
- } else {
- this.$$search = isString(search) ? parseKeyValue(search) : search;
- }
-
- this.$$compose();
- return this;
- },
-
- /**
- * @ngdoc method
- * @name ng.$location#hash
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return hash fragment when called without any parameter.
- *
- * Change hash fragment when called with parameter and return `$location`.
- *
- * @param {string=} hash New hash fragment
- * @return {string} hash
- */
- hash: locationGetterSetter('$$hash', identity),
-
- /**
- * @ngdoc method
- * @name ng.$location#replace
- * @methodOf ng.$location
- *
- * @description
- * If called, all changes to $location during current `$digest` will be replacing current history
- * record, instead of adding new one.
- */
- replace: function() {
- this.$$replace = true;
- return this;
- }
-};
-
-LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
-
-function LocationHashbangInHtml5Url(url, hashPrefix, appBaseUrl, baseExtra) {
- LocationHashbangUrl.apply(this, arguments);
-
-
- this.$$rewriteAppUrl = function(absoluteLinkUrl) {
- if (absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
- return appBaseUrl + baseExtra + '#' + hashPrefix + absoluteLinkUrl.substr(appBaseUrl.length);
- }
- }
-}
-
-LocationHashbangInHtml5Url.prototype = inherit(LocationHashbangUrl.prototype);
-
-function locationGetter(property) {
- return function() {
- return this[property];
- };
-}
-
-
-function locationGetterSetter(property, preprocess) {
- return function(value) {
- if (isUndefined(value))
- return this[property];
-
- this[property] = preprocess(value);
- this.$$compose();
-
- return this;
- };
-}
-
-
-/**
- * @ngdoc object
- * @name ng.$location
- *
- * @requires $browser
- * @requires $sniffer
- * @requires $rootElement
- *
- * @description
- * The $location service parses the URL in the browser address bar (based on the
- * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
- * available to your application. Changes to the URL in the address bar are reflected into
- * $location service and changes to $location are reflected into the browser address bar.
- *
- * **The $location service:**
- *
- * - Exposes the current URL in the browser address bar, so you can
- * - Watch and observe the URL.
- * - Change the URL.
- * - Synchronizes the URL with the browser when the user
- * - Changes the address bar.
- * - Clicks the back or forward button (or clicks a History link).
- * - Clicks on a link.
- * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
- *
- * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
- * Services: Using $location}
- */
-
-/**
- * @ngdoc object
- * @name ng.$locationProvider
- * @description
- * Use the `$locationProvider` to configure how the application deep linking paths are stored.
- */
-function $LocationProvider(){
- var hashPrefix = '',
- html5Mode = false;
-
- /**
- * @ngdoc property
- * @name ng.$locationProvider#hashPrefix
- * @methodOf ng.$locationProvider
- * @description
- * @param {string=} prefix Prefix for hash part (containing path and search)
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
- */
- this.hashPrefix = function(prefix) {
- if (isDefined(prefix)) {
- hashPrefix = prefix;
- return this;
- } else {
- return hashPrefix;
- }
- };
-
- /**
- * @ngdoc property
- * @name ng.$locationProvider#html5Mode
- * @methodOf ng.$locationProvider
- * @description
- * @param {string=} mode Use HTML5 strategy if available.
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
- */
- this.html5Mode = function(mode) {
- if (isDefined(mode)) {
- html5Mode = mode;
- return this;
- } else {
- return html5Mode;
- }
- };
-
- this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
- function( $rootScope, $browser, $sniffer, $rootElement) {
- var $location,
- basePath,
- pathPrefix,
- initUrl = $browser.url(),
- initUrlParts = matchUrl(initUrl),
- appBaseUrl;
-
- if (html5Mode) {
- basePath = $browser.baseHref() || '/';
- pathPrefix = pathPrefixFromBase(basePath);
- appBaseUrl =
- composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
- pathPrefix + '/';
-
- if ($sniffer.history) {
- $location = new LocationUrl(
- convertToHtml5Url(initUrl, basePath, hashPrefix),
- pathPrefix, appBaseUrl);
- } else {
- $location = new LocationHashbangInHtml5Url(
- convertToHashbangUrl(initUrl, basePath, hashPrefix),
- hashPrefix, appBaseUrl, basePath.substr(pathPrefix.length + 1));
- }
- } else {
- appBaseUrl =
- composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
- (initUrlParts.path || '') +
- (initUrlParts.search ? ('?' + initUrlParts.search) : '') +
- '#' + hashPrefix + '/';
-
- $location = new LocationHashbangUrl(initUrl, hashPrefix, appBaseUrl);
- }
-
- $rootElement.bind('click', function(event) {
- // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
- // currently we open nice url link and redirect then
-
- if (event.ctrlKey || event.metaKey || event.which == 2) return;
-
- var elm = jqLite(event.target);
-
- // traverse the DOM up to find first A tag
- while (lowercase(elm[0].nodeName) !== 'a') {
- // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
- if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
- }
-
- var absHref = elm.prop('href'),
- rewrittenUrl = $location.$$rewriteAppUrl(absHref);
-
- if (absHref && !elm.attr('target') && rewrittenUrl) {
- // update location manually
- $location.$$parse(rewrittenUrl);
- $rootScope.$apply();
- event.preventDefault();
- // hack to work around FF6 bug 684208 when scenario runner clicks on links
- window.angular['ff-684208-preventDefault'] = true;
- }
- });
-
-
- // rewrite hashbang url <> html5 url
- if ($location.absUrl() != initUrl) {
- $browser.url($location.absUrl(), true);
- }
-
- // update $location when $browser url changes
- $browser.onUrlChange(function(newUrl) {
- if ($location.absUrl() != newUrl) {
- $rootScope.$evalAsync(function() {
- var oldUrl = $location.absUrl();
-
- $location.$$parse(newUrl);
- afterLocationChange(oldUrl);
- });
- if (!$rootScope.$$phase) $rootScope.$digest();
- }
- });
-
- // update browser
- var changeCounter = 0;
- $rootScope.$watch(function $locationWatch() {
- var oldUrl = $browser.url();
- var currentReplace = $location.$$replace;
-
- if (!changeCounter || oldUrl != $location.absUrl()) {
- changeCounter++;
- $rootScope.$evalAsync(function() {
- if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
- defaultPrevented) {
- $location.$$parse(oldUrl);
- } else {
- $browser.url($location.absUrl(), currentReplace);
- afterLocationChange(oldUrl);
- }
- });
- }
- $location.$$replace = false;
-
- return changeCounter;
- });
-
- return $location;
-
- function afterLocationChange(oldUrl) {
- $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
- }
-}];
-}
-
-/**
- * @ngdoc object
- * @name ng.$log
- * @requires $window
- *
- * @description
- * Simple service for logging. Default implementation writes the message
- * into the browser's console (if present).
- *
- * The main purpose of this service is to simplify debugging and troubleshooting.
- *
- * @example
-
-
- function LogCtrl($scope, $log) {
- $scope.$log = $log;
- $scope.message = 'Hello World!';
- }
-
-
-
-
Reload this page with open console, enter text and hit the log button...
- Message:
-
-
log
-
warn
-
info
-
error
-
-
-
- */
-
-function $LogProvider(){
- this.$get = ['$window', function($window){
- return {
- /**
- * @ngdoc method
- * @name ng.$log#log
- * @methodOf ng.$log
- *
- * @description
- * Write a log message
- */
- log: consoleLog('log'),
-
- /**
- * @ngdoc method
- * @name ng.$log#warn
- * @methodOf ng.$log
- *
- * @description
- * Write a warning message
- */
- warn: consoleLog('warn'),
-
- /**
- * @ngdoc method
- * @name ng.$log#info
- * @methodOf ng.$log
- *
- * @description
- * Write an information message
- */
- info: consoleLog('info'),
-
- /**
- * @ngdoc method
- * @name ng.$log#error
- * @methodOf ng.$log
- *
- * @description
- * Write an error message
- */
- error: consoleLog('error')
- };
-
- function formatError(arg) {
- if (arg instanceof Error) {
- if (arg.stack) {
- arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
- ? 'Error: ' + arg.message + '\n' + arg.stack
- : arg.stack;
- } else if (arg.sourceURL) {
- arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
- }
- }
- return arg;
- }
-
- function consoleLog(type) {
- var console = $window.console || {},
- logFn = console[type] || console.log || noop;
-
- if (logFn.apply) {
- return function() {
- var args = [];
- forEach(arguments, function(arg) {
- args.push(formatError(arg));
- });
- return logFn.apply(console, args);
- };
- }
-
- // we are IE which either doesn't have window.console => this is noop and we do nothing,
- // or we are IE where console.log doesn't have apply so we log at least first 2 args
- return function(arg1, arg2) {
- logFn(arg1, arg2);
- }
- }
- }];
-}
-
-var OPERATORS = {
- 'null':function(){return null;},
- 'true':function(){return true;},
- 'false':function(){return false;},
- undefined:noop,
- '+':function(self, locals, a,b){
- a=a(self, locals); b=b(self, locals);
- if (isDefined(a)) {
- if (isDefined(b)) {
- return a + b;
- }
- return a;
- }
- return isDefined(b)?b:undefined;},
- '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
- '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
- '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
- '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
- '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
- '=':noop,
- '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
- '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
- '<':function(self, locals, a,b){return a(self, locals)':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
- '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
- '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
- '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
- '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
- '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
-// '|':function(self, locals, a,b){return a|b;},
- '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
- '!':function(self, locals, a){return !a(self, locals);}
-};
-var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-
-function lex(text, csp){
- var tokens = [],
- token,
- index = 0,
- json = [],
- ch,
- lastCh = ':'; // can start regexp
-
- while (index < text.length) {
- ch = text.charAt(index);
- if (is('"\'')) {
- readString(ch);
- } else if (isNumber(ch) || is('.') && isNumber(peek())) {
- readNumber();
- } else if (isIdent(ch)) {
- readIdent();
- // identifiers can only be if the preceding char was a { or ,
- if (was('{,') && json[0]=='{' &&
- (token=tokens[tokens.length-1])) {
- token.json = token.text.indexOf('.') == -1;
- }
- } else if (is('(){}[].,;:')) {
- tokens.push({
- index:index,
- text:ch,
- json:(was(':[,') && is('{[')) || is('}]:,')
- });
- if (is('{[')) json.unshift(ch);
- if (is('}]')) json.shift();
- index++;
- } else if (isWhitespace(ch)) {
- index++;
- continue;
- } else {
- var ch2 = ch + peek(),
- fn = OPERATORS[ch],
- fn2 = OPERATORS[ch2];
- if (fn2) {
- tokens.push({index:index, text:ch2, fn:fn2});
- index += 2;
- } else if (fn) {
- tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
- index += 1;
- } else {
- throwError("Unexpected next character ", index, index+1);
- }
- }
- lastCh = ch;
- }
- return tokens;
-
- function is(chars) {
- return chars.indexOf(ch) != -1;
- }
-
- function was(chars) {
- return chars.indexOf(lastCh) != -1;
- }
-
- function peek() {
- return index + 1 < text.length ? text.charAt(index + 1) : false;
- }
- function isNumber(ch) {
- return '0' <= ch && ch <= '9';
- }
- function isWhitespace(ch) {
- return ch == ' ' || ch == '\r' || ch == '\t' ||
- ch == '\n' || ch == '\v' || ch == '\u00A0'; // IE treats non-breaking space as \u00A0
- }
- function isIdent(ch) {
- return 'a' <= ch && ch <= 'z' ||
- 'A' <= ch && ch <= 'Z' ||
- '_' == ch || ch == '$';
- }
- function isExpOperator(ch) {
- return ch == '-' || ch == '+' || isNumber(ch);
- }
-
- function throwError(error, start, end) {
- end = end || index;
- throw Error("Lexer Error: " + error + " at column" +
- (isDefined(start)
- ? "s " + start + "-" + index + " [" + text.substring(start, end) + "]"
- : " " + end) +
- " in expression [" + text + "].");
- }
-
- function readNumber() {
- var number = "";
- var start = index;
- while (index < text.length) {
- var ch = lowercase(text.charAt(index));
- if (ch == '.' || isNumber(ch)) {
- number += ch;
- } else {
- var peekCh = peek();
- if (ch == 'e' && isExpOperator(peekCh)) {
- number += ch;
- } else if (isExpOperator(ch) &&
- peekCh && isNumber(peekCh) &&
- number.charAt(number.length - 1) == 'e') {
- number += ch;
- } else if (isExpOperator(ch) &&
- (!peekCh || !isNumber(peekCh)) &&
- number.charAt(number.length - 1) == 'e') {
- throwError('Invalid exponent');
- } else {
- break;
- }
- }
- index++;
- }
- number = 1 * number;
- tokens.push({index:start, text:number, json:true,
- fn:function() {return number;}});
- }
- function readIdent() {
- var ident = "",
- start = index,
- lastDot, peekIndex, methodName;
-
- while (index < text.length) {
- var ch = text.charAt(index);
- if (ch == '.' || isIdent(ch) || isNumber(ch)) {
- if (ch == '.') lastDot = index;
- ident += ch;
- } else {
- break;
- }
- index++;
- }
-
- //check if this is not a method invocation and if it is back out to last dot
- if (lastDot) {
- peekIndex = index;
- while(peekIndex < text.length) {
- var ch = text.charAt(peekIndex);
- if (ch == '(') {
- methodName = ident.substr(lastDot - start + 1);
- ident = ident.substr(0, lastDot - start);
- index = peekIndex;
- break;
- }
- if(isWhitespace(ch)) {
- peekIndex++;
- } else {
- break;
- }
- }
- }
-
-
- var token = {
- index:start,
- text:ident
- };
-
- if (OPERATORS.hasOwnProperty(ident)) {
- token.fn = token.json = OPERATORS[ident];
- } else {
- var getter = getterFn(ident, csp);
- token.fn = extend(function(self, locals) {
- return (getter(self, locals));
- }, {
- assign: function(self, value) {
- return setter(self, ident, value);
- }
- });
- }
-
- tokens.push(token);
-
- if (methodName) {
- tokens.push({
- index:lastDot,
- text: '.',
- json: false
- });
- tokens.push({
- index: lastDot + 1,
- text: methodName,
- json: false
- });
- }
- }
-
- function readString(quote) {
- var start = index;
- index++;
- var string = "";
- var rawString = quote;
- var escape = false;
- while (index < text.length) {
- var ch = text.charAt(index);
- rawString += ch;
- if (escape) {
- if (ch == 'u') {
- var hex = text.substring(index + 1, index + 5);
- if (!hex.match(/[\da-f]{4}/i))
- throwError( "Invalid unicode escape [\\u" + hex + "]");
- index += 4;
- string += String.fromCharCode(parseInt(hex, 16));
- } else {
- var rep = ESCAPE[ch];
- if (rep) {
- string += rep;
- } else {
- string += ch;
- }
- }
- escape = false;
- } else if (ch == '\\') {
- escape = true;
- } else if (ch == quote) {
- index++;
- tokens.push({
- index:start,
- text:rawString,
- string:string,
- json:true,
- fn:function() { return string; }
- });
- return;
- } else {
- string += ch;
- }
- index++;
- }
- throwError("Unterminated quote", start);
- }
-}
-
-/////////////////////////////////////////
-
-function parser(text, json, $filter, csp){
- var ZERO = valueFn(0),
- value,
- tokens = lex(text, csp),
- assignment = _assignment,
- functionCall = _functionCall,
- fieldAccess = _fieldAccess,
- objectIndex = _objectIndex,
- filterChain = _filterChain;
-
- if(json){
- // The extra level of aliasing is here, just in case the lexer misses something, so that
- // we prevent any accidental execution in JSON.
- assignment = logicalOR;
- functionCall =
- fieldAccess =
- objectIndex =
- filterChain =
- function() { throwError("is not valid json", {text:text, index:0}); };
- value = primary();
- } else {
- value = statements();
- }
- if (tokens.length !== 0) {
- throwError("is an unexpected token", tokens[0]);
- }
- return value;
-
- ///////////////////////////////////
- function throwError(msg, token) {
- throw Error("Syntax Error: Token '" + token.text +
- "' " + msg + " at column " +
- (token.index + 1) + " of the expression [" +
- text + "] starting at [" + text.substring(token.index) + "].");
- }
-
- function peekToken() {
- if (tokens.length === 0)
- throw Error("Unexpected end of expression: " + text);
- return tokens[0];
- }
-
- function peek(e1, e2, e3, e4) {
- if (tokens.length > 0) {
- var token = tokens[0];
- var t = token.text;
- if (t==e1 || t==e2 || t==e3 || t==e4 ||
- (!e1 && !e2 && !e3 && !e4)) {
- return token;
- }
- }
- return false;
- }
-
- function expect(e1, e2, e3, e4){
- var token = peek(e1, e2, e3, e4);
- if (token) {
- if (json && !token.json) {
- throwError("is not valid json", token);
- }
- tokens.shift();
- return token;
- }
- return false;
- }
-
- function consume(e1){
- if (!expect(e1)) {
- throwError("is unexpected, expecting [" + e1 + "]", peek());
- }
- }
-
- function unaryFn(fn, right) {
- return function(self, locals) {
- return fn(self, locals, right);
- };
- }
-
- function binaryFn(left, fn, right) {
- return function(self, locals) {
- return fn(self, locals, left, right);
- };
- }
-
- function statements() {
- var statements = [];
- while(true) {
- if (tokens.length > 0 && !peek('}', ')', ';', ']'))
- statements.push(filterChain());
- if (!expect(';')) {
- // optimize for the common case where there is only one statement.
- // TODO(size): maybe we should not support multiple statements?
- return statements.length == 1
- ? statements[0]
- : function(self, locals){
- var value;
- for ( var i = 0; i < statements.length; i++) {
- var statement = statements[i];
- if (statement)
- value = statement(self, locals);
- }
- return value;
- };
- }
- }
- }
-
- function _filterChain() {
- var left = expression();
- var token;
- while(true) {
- if ((token = expect('|'))) {
- left = binaryFn(left, token.fn, filter());
- } else {
- return left;
- }
- }
- }
-
- function filter() {
- var token = expect();
- var fn = $filter(token.text);
- var argsFn = [];
- while(true) {
- if ((token = expect(':'))) {
- argsFn.push(expression());
- } else {
- var fnInvoke = function(self, locals, input){
- var args = [input];
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self, locals));
- }
- return fn.apply(self, args);
- };
- return function() {
- return fnInvoke;
- };
- }
- }
- }
-
- function expression() {
- return assignment();
- }
-
- function _assignment() {
- var left = logicalOR();
- var right;
- var token;
- if ((token = expect('='))) {
- if (!left.assign) {
- throwError("implies assignment but [" +
- text.substring(0, token.index) + "] can not be assigned to", token);
- }
- right = logicalOR();
- return function(self, locals){
- return left.assign(self, right(self, locals), locals);
- };
- } else {
- return left;
- }
- }
-
- function logicalOR() {
- var left = logicalAND();
- var token;
- while(true) {
- if ((token = expect('||'))) {
- left = binaryFn(left, token.fn, logicalAND());
- } else {
- return left;
- }
- }
- }
-
- function logicalAND() {
- var left = equality();
- var token;
- if ((token = expect('&&'))) {
- left = binaryFn(left, token.fn, logicalAND());
- }
- return left;
- }
-
- function equality() {
- var left = relational();
- var token;
- if ((token = expect('==','!='))) {
- left = binaryFn(left, token.fn, equality());
- }
- return left;
- }
-
- function relational() {
- var left = additive();
- var token;
- if ((token = expect('<', '>', '<=', '>='))) {
- left = binaryFn(left, token.fn, relational());
- }
- return left;
- }
-
- function additive() {
- var left = multiplicative();
- var token;
- while ((token = expect('+','-'))) {
- left = binaryFn(left, token.fn, multiplicative());
- }
- return left;
- }
-
- function multiplicative() {
- var left = unary();
- var token;
- while ((token = expect('*','/','%'))) {
- left = binaryFn(left, token.fn, unary());
- }
- return left;
- }
-
- function unary() {
- var token;
- if (expect('+')) {
- return primary();
- } else if ((token = expect('-'))) {
- return binaryFn(ZERO, token.fn, unary());
- } else if ((token = expect('!'))) {
- return unaryFn(token.fn, unary());
- } else {
- return primary();
- }
- }
-
-
- function primary() {
- var primary;
- if (expect('(')) {
- primary = filterChain();
- consume(')');
- } else if (expect('[')) {
- primary = arrayDeclaration();
- } else if (expect('{')) {
- primary = object();
- } else {
- var token = expect();
- primary = token.fn;
- if (!primary) {
- throwError("not a primary expression", token);
- }
- }
-
- var next, context;
- while ((next = expect('(', '[', '.'))) {
- if (next.text === '(') {
- primary = functionCall(primary, context);
- context = null;
- } else if (next.text === '[') {
- context = primary;
- primary = objectIndex(primary);
- } else if (next.text === '.') {
- context = primary;
- primary = fieldAccess(primary);
- } else {
- throwError("IMPOSSIBLE");
- }
- }
- return primary;
- }
-
- function _fieldAccess(object) {
- var field = expect().text;
- var getter = getterFn(field, csp);
- return extend(
- function(self, locals) {
- return getter(object(self, locals), locals);
- },
- {
- assign:function(self, value, locals) {
- return setter(object(self, locals), field, value);
- }
- }
- );
- }
-
- function _objectIndex(obj) {
- var indexFn = expression();
- consume(']');
- return extend(
- function(self, locals){
- var o = obj(self, locals),
- i = indexFn(self, locals),
- v, p;
-
- if (!o) return undefined;
- v = o[i];
- if (v && v.then) {
- p = v;
- if (!('$$v' in v)) {
- p.$$v = undefined;
- p.then(function(val) { p.$$v = val; });
- }
- v = v.$$v;
- }
- return v;
- }, {
- assign:function(self, value, locals){
- return obj(self, locals)[indexFn(self, locals)] = value;
- }
- });
- }
-
- function _functionCall(fn, contextGetter) {
- var argsFn = [];
- if (peekToken().text != ')') {
- do {
- argsFn.push(expression());
- } while (expect(','));
- }
- consume(')');
- return function(self, locals){
- var args = [],
- context = contextGetter ? contextGetter(self, locals) : self;
-
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self, locals));
- }
- var fnPtr = fn(self, locals) || noop;
- // IE stupidity!
- return fnPtr.apply
- ? fnPtr.apply(context, args)
- : fnPtr(args[0], args[1], args[2], args[3], args[4]);
- };
- }
-
- // This is used with json array declaration
- function arrayDeclaration () {
- var elementFns = [];
- if (peekToken().text != ']') {
- do {
- elementFns.push(expression());
- } while (expect(','));
- }
- consume(']');
- return function(self, locals){
- var array = [];
- for ( var i = 0; i < elementFns.length; i++) {
- array.push(elementFns[i](self, locals));
- }
- return array;
- };
- }
-
- function object () {
- var keyValues = [];
- if (peekToken().text != '}') {
- do {
- var token = expect(),
- key = token.string || token.text;
- consume(":");
- var value = expression();
- keyValues.push({key:key, value:value});
- } while (expect(','));
- }
- consume('}');
- return function(self, locals){
- var object = {};
- for ( var i = 0; i < keyValues.length; i++) {
- var keyValue = keyValues[i];
- var value = keyValue.value(self, locals);
- object[keyValue.key] = value;
- }
- return object;
- };
- }
-}
-
-//////////////////////////////////////////////////
-// Parser helper functions
-//////////////////////////////////////////////////
-
-function setter(obj, path, setValue) {
- var element = path.split('.');
- for (var i = 0; element.length > 1; i++) {
- var key = element.shift();
- var propertyObj = obj[key];
- if (!propertyObj) {
- propertyObj = {};
- obj[key] = propertyObj;
- }
- obj = propertyObj;
- }
- obj[element.shift()] = setValue;
- return setValue;
-}
-
-/**
- * Return the value accesible from the object by path. Any undefined traversals are ignored
- * @param {Object} obj starting object
- * @param {string} path path to traverse
- * @param {boolean=true} bindFnToScope
- * @returns value as accesbile by path
- */
-//TODO(misko): this function needs to be removed
-function getter(obj, path, bindFnToScope) {
- if (!path) return obj;
- var keys = path.split('.');
- var key;
- var lastInstance = obj;
- var len = keys.length;
-
- for (var i = 0; i < len; i++) {
- key = keys[i];
- if (obj) {
- obj = (lastInstance = obj)[key];
- }
- }
- if (!bindFnToScope && isFunction(obj)) {
- return bind(lastInstance, obj);
- }
- return obj;
-}
-
-var getterFnCache = {};
-
-/**
- * Implementation of the "Black Hole" variant from:
- * - http://jsperf.com/angularjs-parse-getter/4
- * - http://jsperf.com/path-evaluation-simplified/7
- */
-function cspSafeGetterFn(key0, key1, key2, key3, key4) {
- return function(scope, locals) {
- var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
- promise;
-
- if (pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key0];
- if (pathVal && pathVal.then) {
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key1];
- if (pathVal && pathVal.then) {
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key2];
- if (pathVal && pathVal.then) {
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key3];
- if (pathVal && pathVal.then) {
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key4];
- if (pathVal && pathVal.then) {
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- return pathVal;
- };
-};
-
-function getterFn(path, csp) {
- if (getterFnCache.hasOwnProperty(path)) {
- return getterFnCache[path];
- }
-
- var pathKeys = path.split('.'),
- pathKeysLength = pathKeys.length,
- fn;
-
- if (csp) {
- fn = (pathKeysLength < 6)
- ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
- : function(scope, locals) {
- var i = 0, val
- do {
- val = cspSafeGetterFn(
- pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
- )(scope, locals);
-
- locals = undefined; // clear after first iteration
- scope = val;
- } while (i < pathKeysLength);
- return val;
- }
- } else {
- var code = 'var l, fn, p;\n';
- forEach(pathKeys, function(key, index) {
- code += 'if(s === null || s === undefined) return s;\n' +
- 'l=s;\n' +
- 's='+ (index
- // we simply dereference 's' on any .dot notation
- ? 's'
- // but if we are first then we check locals first, and if so read it first
- : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
- 'if (s && s.then) {\n' +
- ' if (!("$$v" in s)) {\n' +
- ' p=s;\n' +
- ' p.$$v = undefined;\n' +
- ' p.then(function(v) {p.$$v=v;});\n' +
- '}\n' +
- ' s=s.$$v\n' +
- '}\n';
- });
- code += 'return s;';
- fn = Function('s', 'k', code); // s=scope, k=locals
- fn.toString = function() { return code; };
- }
-
- return getterFnCache[path] = fn;
-}
-
-///////////////////////////////////
-
-/**
- * @ngdoc function
- * @name ng.$parse
- * @function
- *
- * @description
- *
- * Converts Angular {@link guide/expression expression} into a function.
- *
- *
- * var getter = $parse('user.name');
- * var setter = getter.assign;
- * var context = {user:{name:'angular'}};
- * var locals = {user:{name:'local'}};
- *
- * expect(getter(context)).toEqual('angular');
- * setter(context, 'newValue');
- * expect(context.user.name).toEqual('newValue');
- * expect(getter(context, locals)).toEqual('local');
- *
- *
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (tipically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- *
- * The return function also has an `assign` property, if the expression is assignable, which
- * allows one to set values to expressions.
- *
- */
-function $ParseProvider() {
- var cache = {};
- this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
- return function(exp) {
- switch(typeof exp) {
- case 'string':
- return cache.hasOwnProperty(exp)
- ? cache[exp]
- : cache[exp] = parser(exp, false, $filter, $sniffer.csp);
- case 'function':
- return exp;
- default:
- return noop;
- }
- };
- }];
-}
-
-/**
- * @ngdoc service
- * @name ng.$q
- * @requires $rootScope
- *
- * @description
- * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
- *
- * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
- * interface for interacting with an object that represents the result of an action that is
- * performed asynchronously, and may or may not be finished at any given point in time.
- *
- * From the perspective of dealing with error handling, deferred and promise APIs are to
- * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
- *
- *
- * // for the purpose of this example let's assume that variables `$q` and `scope` are
- * // available in the current lexical scope (they could have been injected or passed in).
- *
- * function asyncGreet(name) {
- * var deferred = $q.defer();
- *
- * setTimeout(function() {
- * // since this fn executes async in a future turn of the event loop, we need to wrap
- * // our code into an $apply call so that the model changes are properly observed.
- * scope.$apply(function() {
- * if (okToGreet(name)) {
- * deferred.resolve('Hello, ' + name + '!');
- * } else {
- * deferred.reject('Greeting ' + name + ' is not allowed.');
- * }
- * });
- * }, 1000);
- *
- * return deferred.promise;
- * }
- *
- * var promise = asyncGreet('Robin Hood');
- * promise.then(function(greeting) {
- * alert('Success: ' + greeting);
- * }, function(reason) {
- * alert('Failed: ' + reason);
- * });
- *
- *
- * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
- * comes in the way of
- * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
- *
- * Additionally the promise api allows for composition that is very hard to do with the
- * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
- * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
- * section on serial or parallel joining of promises.
- *
- *
- * # The Deferred API
- *
- * A new instance of deferred is constructed by calling `$q.defer()`.
- *
- * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
- * that can be used for signaling the successful or unsuccessful completion of the task.
- *
- * **Methods**
- *
- * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
- * constructed via `$q.reject`, the promise will be rejected instead.
- * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
- * resolving it with a rejection constructed via `$q.reject`.
- *
- * **Properties**
- *
- * - promise – `{Promise}` – promise object associated with this deferred.
- *
- *
- * # The Promise API
- *
- * A new promise instance is created when a deferred instance is created and can be retrieved by
- * calling `deferred.promise`.
- *
- * The purpose of the promise object is to allow for interested parties to get access to the result
- * of the deferred task when it completes.
- *
- * **Methods**
- *
- * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved
- * or rejected calls one of the success or error callbacks asynchronously as soon as the result
- * is available. The callbacks are called with a single argument the result or rejection reason.
- *
- * This method *returns a new promise* which is resolved or rejected via the return value of the
- * `successCallback` or `errorCallback`.
- *
- *
- * # Chaining promises
- *
- * Because calling `then` api of a promise returns a new derived promise, it is easily possible
- * to create a chain of promises:
- *
- *
- * promiseB = promiseA.then(function(result) {
- * return result + 1;
- * });
- *
- * // promiseB will be resolved immediately after promiseA is resolved and its value will be
- * // the result of promiseA incremented by 1
- *
- *
- * It is possible to create chains of any length and since a promise can be resolved with another
- * promise (which will defer its resolution further), it is possible to pause/defer resolution of
- * the promises at any point in the chain. This makes it possible to implement powerful apis like
- * $http's response interceptors.
- *
- *
- * # Differences between Kris Kowal's Q and $q
- *
- * There are three main differences:
- *
- * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
- * mechanism in angular, which means faster propagation of resolution or rejection into your
- * models and avoiding unnecessary browser repaints, which would result in flickering UI.
- * - $q promises are recognized by the templating engine in angular, which means that in templates
- * you can treat promises attached to a scope as if they were the resulting values.
- * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains
- * all the important functionality needed for common async tasks.
- *
- * # Testing
- *
- *
- * it('should simulate promise', inject(function($q, $rootScope) {
- * var deferred = $q.defer();
- * var promise = deferred.promise;
- * var resolvedValue;
- *
- * promise.then(function(value) { resolvedValue = value; });
- * expect(resolvedValue).toBeUndefined();
- *
- * // Simulate resolving of promise
- * deferred.resolve(123);
- * // Note that the 'then' function does not get called synchronously.
- * // This is because we want the promise API to always be async, whether or not
- * // it got called synchronously or asynchronously.
- * expect(resolvedValue).toBeUndefined();
- *
- * // Propagate promise resolution to 'then' functions using $apply().
- * $rootScope.$apply();
- * expect(resolvedValue).toEqual(123);
- * });
- *
- */
-function $QProvider() {
-
- this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
- return qFactory(function(callback) {
- $rootScope.$evalAsync(callback);
- }, $exceptionHandler);
- }];
-}
-
-
-/**
- * Constructs a promise manager.
- *
- * @param {function(function)} nextTick Function for executing functions in the next turn.
- * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
- * debugging purposes.
- * @returns {object} Promise manager.
- */
-function qFactory(nextTick, exceptionHandler) {
-
- /**
- * @ngdoc
- * @name ng.$q#defer
- * @methodOf ng.$q
- * @description
- * Creates a `Deferred` object which represents a task which will finish in the future.
- *
- * @returns {Deferred} Returns a new instance of deferred.
- */
- var defer = function() {
- var pending = [],
- value, deferred;
-
- deferred = {
-
- resolve: function(val) {
- if (pending) {
- var callbacks = pending;
- pending = undefined;
- value = ref(val);
-
- if (callbacks.length) {
- nextTick(function() {
- var callback;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- callback = callbacks[i];
- value.then(callback[0], callback[1]);
- }
- });
- }
- }
- },
-
-
- reject: function(reason) {
- deferred.resolve(reject(reason));
- },
-
-
- promise: {
- then: function(callback, errback) {
- var result = defer();
-
- var wrappedCallback = function(value) {
- try {
- result.resolve((callback || defaultCallback)(value));
- } catch(e) {
- exceptionHandler(e);
- result.reject(e);
- }
- };
-
- var wrappedErrback = function(reason) {
- try {
- result.resolve((errback || defaultErrback)(reason));
- } catch(e) {
- exceptionHandler(e);
- result.reject(e);
- }
- };
-
- if (pending) {
- pending.push([wrappedCallback, wrappedErrback]);
- } else {
- value.then(wrappedCallback, wrappedErrback);
- }
-
- return result.promise;
- }
- }
- };
-
- return deferred;
- };
-
-
- var ref = function(value) {
- if (value && value.then) return value;
- return {
- then: function(callback) {
- var result = defer();
- nextTick(function() {
- result.resolve(callback(value));
- });
- return result.promise;
- }
- };
- };
-
-
- /**
- * @ngdoc
- * @name ng.$q#reject
- * @methodOf ng.$q
- * @description
- * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
- * used to forward rejection in a chain of promises. If you are dealing with the last promise in
- * a promise chain, you don't need to worry about it.
- *
- * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
- * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
- * a promise error callback and you want to forward the error to the promise derived from the
- * current promise, you have to "rethrow" the error by returning a rejection constructed via
- * `reject`.
- *
- *
- * promiseB = promiseA.then(function(result) {
- * // success: do something and resolve promiseB
- * // with the old or a new result
- * return result;
- * }, function(reason) {
- * // error: handle the error if possible and
- * // resolve promiseB with newPromiseOrValue,
- * // otherwise forward the rejection to promiseB
- * if (canHandle(reason)) {
- * // handle the error and recover
- * return newPromiseOrValue;
- * }
- * return $q.reject(reason);
- * });
- *
- *
- * @param {*} reason Constant, message, exception or an object representing the rejection reason.
- * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
- */
- var reject = function(reason) {
- return {
- then: function(callback, errback) {
- var result = defer();
- nextTick(function() {
- result.resolve((errback || defaultErrback)(reason));
- });
- return result.promise;
- }
- };
- };
-
-
- /**
- * @ngdoc
- * @name ng.$q#when
- * @methodOf ng.$q
- * @description
- * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
- * This is useful when you are dealing with an object that might or might not be a promise, or if
- * the promise comes from a source that can't be trusted.
- *
- * @param {*} value Value or a promise
- * @returns {Promise} Returns a single promise that will be resolved with an array of values,
- * each value corresponding to the promise at the same index in the `promises` array. If any of
- * the promises is resolved with a rejection, this resulting promise will be resolved with the
- * same rejection.
- */
- var when = function(value, callback, errback) {
- var result = defer(),
- done;
-
- var wrappedCallback = function(value) {
- try {
- return (callback || defaultCallback)(value);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- var wrappedErrback = function(reason) {
- try {
- return (errback || defaultErrback)(reason);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- nextTick(function() {
- ref(value).then(function(value) {
- if (done) return;
- done = true;
- result.resolve(ref(value).then(wrappedCallback, wrappedErrback));
- }, function(reason) {
- if (done) return;
- done = true;
- result.resolve(wrappedErrback(reason));
- });
- });
-
- return result.promise;
- };
-
-
- function defaultCallback(value) {
- return value;
- }
-
-
- function defaultErrback(reason) {
- return reject(reason);
- }
-
-
- /**
- * @ngdoc
- * @name ng.$q#all
- * @methodOf ng.$q
- * @description
- * Combines multiple promises into a single promise that is resolved when all of the input
- * promises are resolved.
- *
- * @param {Array.} promises An array of promises.
- * @returns {Promise} Returns a single promise that will be resolved with an array of values,
- * each value corresponding to the promise at the same index in the `promises` array. If any of
- * the promises is resolved with a rejection, this resulting promise will be resolved with the
- * same rejection.
- */
- function all(promises) {
- var deferred = defer(),
- counter = promises.length,
- results = [];
-
- if (counter) {
- forEach(promises, function(promise, index) {
- ref(promise).then(function(value) {
- if (index in results) return;
- results[index] = value;
- if (!(--counter)) deferred.resolve(results);
- }, function(reason) {
- if (index in results) return;
- deferred.reject(reason);
- });
- });
- } else {
- deferred.resolve(results);
- }
-
- return deferred.promise;
- }
-
- return {
- defer: defer,
- reject: reject,
- when: when,
- all: all
- };
-}
-
-/**
- * @ngdoc object
- * @name ng.$routeProvider
- * @function
- *
- * @description
- *
- * Used for configuring routes. See {@link ng.$route $route} for an example.
- */
-function $RouteProvider(){
- var routes = {};
-
- /**
- * @ngdoc method
- * @name ng.$routeProvider#when
- * @methodOf ng.$routeProvider
- *
- * @param {string} path Route path (matched against `$location.path`). If `$location.path`
- * contains redundant trailing slash or is missing one, the route will still match and the
- * `$location.path` will be updated to add or drop the trailing slash to exactly match the
- * route definition.
- *
- * `path` can contain named groups starting with a colon (`:name`). All characters up to the
- * next slash are matched and stored in `$routeParams` under the given `name` when the route
- * matches.
- *
- * @param {Object} route Mapping information to be assigned to `$route.current` on route
- * match.
- *
- * Object properties:
- *
- * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
- * created scope or the name of a {@link angular.Module#controller registered controller}
- * if passed as a string.
- * - `template` – `{string=}` – html template as a string that should be used by
- * {@link ng.directive:ngView ngView} or
- * {@link ng.directive:ngInclude ngInclude} directives.
- * this property takes precedence over `templateUrl`.
- * - `templateUrl` – `{string=}` – path to an html template that should be used by
- * {@link ng.directive:ngView ngView}.
- * - `resolve` - `{Object.=}` - An optional map of dependencies which should
- * be injected into the controller. If any of these dependencies are promises, they will be
- * resolved and converted to a value before the controller is instantiated and the
- * `$routeChangeSuccess` event is fired. The map object is:
- *
- * - `key` – `{string}`: a name of a dependency to be injected into the controller.
- * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
- * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
- * and the return value is treated as the dependency. If the result is a promise, it is resolved
- * before its value is injected into the controller.
- *
- * - `redirectTo` – {(string|function())=} – value to update
- * {@link ng.$location $location} path with and trigger route redirection.
- *
- * If `redirectTo` is a function, it will be called with the following parameters:
- *
- * - `{Object.}` - route parameters extracted from the current
- * `$location.path()` by applying the current route templateUrl.
- * - `{string}` - current `$location.path()`
- * - `{Object}` - current `$location.search()`
- *
- * The custom `redirectTo` function is expected to return a string which will be used
- * to update `$location.path()` and `$location.search()`.
- *
- * - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
- * changes.
- *
- * If the option is set to `false` and url in the browser changes, then
- * `$routeUpdate` event is broadcasted on the root scope.
- *
- * @returns {Object} self
- *
- * @description
- * Adds a new route definition to the `$route` service.
- */
- this.when = function(path, route) {
- routes[path] = extend({reloadOnSearch: true}, route);
-
- // create redirection for trailing slashes
- if (path) {
- var redirectPath = (path[path.length-1] == '/')
- ? path.substr(0, path.length-1)
- : path +'/';
-
- routes[redirectPath] = {redirectTo: path};
- }
-
- return this;
- };
-
- /**
- * @ngdoc method
- * @name ng.$routeProvider#otherwise
- * @methodOf ng.$routeProvider
- *
- * @description
- * Sets route definition that will be used on route change when no other route definition
- * is matched.
- *
- * @param {Object} params Mapping information to be assigned to `$route.current`.
- * @returns {Object} self
- */
- this.otherwise = function(params) {
- this.when(null, params);
- return this;
- };
-
-
- this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache',
- function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache) {
-
- /**
- * @ngdoc object
- * @name ng.$route
- * @requires $location
- * @requires $routeParams
- *
- * @property {Object} current Reference to the current route definition.
- * The route definition contains:
- *
- * - `controller`: The controller constructor as define in route definition.
- * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
- * controller instantiation. The `locals` contain
- * the resolved values of the `resolve` map. Additionally the `locals` also contain:
- *
- * - `$scope` - The current route scope.
- * - `$template` - The current route template HTML.
- *
- * @property {Array.} routes Array of all configured routes.
- *
- * @description
- * Is used for deep-linking URLs to controllers and views (HTML partials).
- * It watches `$location.url()` and tries to map the path to an existing route definition.
- *
- * You can define routes through {@link ng.$routeProvider $routeProvider}'s API.
- *
- * The `$route` service is typically used in conjunction with {@link ng.directive:ngView ngView}
- * directive and the {@link ng.$routeParams $routeParams} service.
- *
- * @example
- This example shows how changing the URL hash causes the `$route` to match a route against the
- URL, and the `ngView` pulls in the partial.
-
- Note that this example is using {@link ng.directive:script inlined templates}
- to get it working on jsfiddle as well.
-
-
-
-
- Choose:
-
Moby |
-
Moby: Ch1 |
-
Gatsby |
-
Gatsby: Ch4 |
-
Scarlet Letter
-
-
-
-
-
$location.path() = {{$location.path()}}
-
$route.current.templateUrl = {{$route.current.templateUrl}}
-
$route.current.params = {{$route.current.params}}
-
$route.current.scope.name = {{$route.current.scope.name}}
-
$routeParams = {{$routeParams}}
-
-
-
-
- controller: {{name}}
- Book Id: {{params.bookId}}
-
-
-
- controller: {{name}}
- Book Id: {{params.bookId}}
- Chapter Id: {{params.chapterId}}
-
-
-
- angular.module('ngView', [], function($routeProvider, $locationProvider) {
- $routeProvider.when('/Book/:bookId', {
- templateUrl: 'book.html',
- controller: BookCntl,
- resolve: {
- // I will cause a 1 second delay
- delay: function($q, $timeout) {
- var delay = $q.defer();
- $timeout(delay.resolve, 1000);
- return delay.promise;
- }
- }
- });
- $routeProvider.when('/Book/:bookId/ch/:chapterId', {
- templateUrl: 'chapter.html',
- controller: ChapterCntl
- });
-
- // configure html5 to get links working on jsfiddle
- $locationProvider.html5Mode(true);
- });
-
- function MainCntl($scope, $route, $routeParams, $location) {
- $scope.$route = $route;
- $scope.$location = $location;
- $scope.$routeParams = $routeParams;
- }
-
- function BookCntl($scope, $routeParams) {
- $scope.name = "BookCntl";
- $scope.params = $routeParams;
- }
-
- function ChapterCntl($scope, $routeParams) {
- $scope.name = "ChapterCntl";
- $scope.params = $routeParams;
- }
-
-
-
- it('should load and compile correct template', function() {
- element('a:contains("Moby: Ch1")').click();
- var content = element('.doc-example-live [ng-view]').text();
- expect(content).toMatch(/controller\: ChapterCntl/);
- expect(content).toMatch(/Book Id\: Moby/);
- expect(content).toMatch(/Chapter Id\: 1/);
-
- element('a:contains("Scarlet")').click();
- sleep(2); // promises are not part of scenario waiting
- content = element('.doc-example-live [ng-view]').text();
- expect(content).toMatch(/controller\: BookCntl/);
- expect(content).toMatch(/Book Id\: Scarlet/);
- });
-
-
- */
-
- /**
- * @ngdoc event
- * @name ng.$route#$routeChangeStart
- * @eventOf ng.$route
- * @eventType broadcast on root scope
- * @description
- * Broadcasted before a route change. At this point the route services starts
- * resolving all of the dependencies needed for the route change to occurs.
- * Typically this involves fetching the view template as well as any dependencies
- * defined in `resolve` route property. Once all of the dependencies are resolved
- * `$routeChangeSuccess` is fired.
- *
- * @param {Route} next Future route information.
- * @param {Route} current Current route information.
- */
-
- /**
- * @ngdoc event
- * @name ng.$route#$routeChangeSuccess
- * @eventOf ng.$route
- * @eventType broadcast on root scope
- * @description
- * Broadcasted after a route dependencies are resolved.
- * {@link ng.directive:ngView ngView} listens for the directive
- * to instantiate the controller and render the view.
- *
- * @param {Route} current Current route information.
- * @param {Route} previous Previous route information.
- */
-
- /**
- * @ngdoc event
- * @name ng.$route#$routeChangeError
- * @eventOf ng.$route
- * @eventType broadcast on root scope
- * @description
- * Broadcasted if any of the resolve promises are rejected.
- *
- * @param {Route} current Current route information.
- * @param {Route} previous Previous route information.
- * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
- */
-
- /**
- * @ngdoc event
- * @name ng.$route#$routeUpdate
- * @eventOf ng.$route
- * @eventType broadcast on root scope
- * @description
- *
- * The `reloadOnSearch` property has been set to false, and we are reusing the same
- * instance of the Controller.
- */
-
- var forceReload = false,
- $route = {
- routes: routes,
-
- /**
- * @ngdoc method
- * @name ng.$route#reload
- * @methodOf ng.$route
- *
- * @description
- * Causes `$route` service to reload the current route even if
- * {@link ng.$location $location} hasn't changed.
- *
- * As a result of that, {@link ng.directive:ngView ngView}
- * creates new scope, reinstantiates the controller.
- */
- reload: function() {
- forceReload = true;
- $rootScope.$evalAsync(updateRoute);
- }
- };
-
- $rootScope.$on('$locationChangeSuccess', updateRoute);
-
- return $route;
-
- /////////////////////////////////////////////////////
-
- /**
- * @param on {string} current url
- * @param when {string} route when template to match the url against
- * @return {?Object}
- */
- function switchRouteMatcher(on, when) {
- // TODO(i): this code is convoluted and inefficient, we should construct the route matching
- // regex only once and then reuse it
-
- // Escape regexp special characters.
- when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
- var regex = '',
- params = [],
- dst = {};
-
- var re = /:(\w+)/g,
- paramMatch,
- lastMatchedIndex = 0;
-
- while ((paramMatch = re.exec(when)) !== null) {
- // Find each :param in `when` and replace it with a capturing group.
- // Append all other sections of when unchanged.
- regex += when.slice(lastMatchedIndex, paramMatch.index);
- regex += '([^\\/]*)';
- params.push(paramMatch[1]);
- lastMatchedIndex = re.lastIndex;
- }
- // Append trailing path part.
- regex += when.substr(lastMatchedIndex);
-
- var match = on.match(new RegExp(regex));
- if (match) {
- forEach(params, function(name, index) {
- dst[name] = match[index + 1];
- });
- }
- return match ? dst : null;
- }
-
- function updateRoute() {
- var next = parseRoute(),
- last = $route.current;
-
- if (next && last && next.$route === last.$route
- && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
- last.params = next.params;
- copy(last.params, $routeParams);
- $rootScope.$broadcast('$routeUpdate', last);
- } else if (next || last) {
- forceReload = false;
- $rootScope.$broadcast('$routeChangeStart', next, last);
- $route.current = next;
- if (next) {
- if (next.redirectTo) {
- if (isString(next.redirectTo)) {
- $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
- .replace();
- } else {
- $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
- .replace();
- }
- }
- }
-
- $q.when(next).
- then(function() {
- if (next) {
- var keys = [],
- values = [],
- template;
-
- forEach(next.resolve || {}, function(value, key) {
- keys.push(key);
- values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
- });
- if (isDefined(template = next.template)) {
- } else if (isDefined(template = next.templateUrl)) {
- template = $http.get(template, {cache: $templateCache}).
- then(function(response) { return response.data; });
- }
- if (isDefined(template)) {
- keys.push('$template');
- values.push(template);
- }
- return $q.all(values).then(function(values) {
- var locals = {};
- forEach(values, function(value, index) {
- locals[keys[index]] = value;
- });
- return locals;
- });
- }
- }).
- // after route change
- then(function(locals) {
- if (next == $route.current) {
- if (next) {
- next.locals = locals;
- copy(next.params, $routeParams);
- }
- $rootScope.$broadcast('$routeChangeSuccess', next, last);
- }
- }, function(error) {
- if (next == $route.current) {
- $rootScope.$broadcast('$routeChangeError', next, last, error);
- }
- });
- }
- }
-
-
- /**
- * @returns the current active route, by matching it against the URL
- */
- function parseRoute() {
- // Match a route
- var params, match;
- forEach(routes, function(route, path) {
- if (!match && (params = switchRouteMatcher($location.path(), path))) {
- match = inherit(route, {
- params: extend({}, $location.search(), params),
- pathParams: params});
- match.$route = route;
- }
- });
- // No route matched; fallback to "otherwise" route
- return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
- }
-
- /**
- * @returns interpolation of the redirect path with the parametrs
- */
- function interpolate(string, params) {
- var result = [];
- forEach((string||'').split(':'), function(segment, i) {
- if (i == 0) {
- result.push(segment);
- } else {
- var segmentMatch = segment.match(/(\w+)(.*)/);
- var key = segmentMatch[1];
- result.push(params[key]);
- result.push(segmentMatch[2] || '');
- delete params[key];
- }
- });
- return result.join('');
- }
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$routeParams
- * @requires $route
- *
- * @description
- * Current set of route parameters. The route parameters are a combination of the
- * {@link ng.$location $location} `search()`, and `path()`. The `path` parameters
- * are extracted when the {@link ng.$route $route} path is matched.
- *
- * In case of parameter name collision, `path` params take precedence over `search` params.
- *
- * The service guarantees that the identity of the `$routeParams` object will remain unchanged
- * (but its properties will likely change) even when a route change occurs.
- *
- * @example
- *
- * // Given:
- * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
- * // Route: /Chapter/:chapterId/Section/:sectionId
- * //
- * // Then
- * $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
- *
- */
-function $RouteParamsProvider() {
- this.$get = valueFn({});
-}
-
-/**
- * DESIGN NOTES
- *
- * The design decisions behind the scope ware heavily favored for speed and memory consumption.
- *
- * The typical use of scope is to watch the expressions, which most of the time return the same
- * value as last time so we optimize the operation.
- *
- * Closures construction is expensive from speed as well as memory:
- * - no closures, instead ups prototypical inheritance for API
- * - Internal state needs to be stored on scope directly, which means that private state is
- * exposed as $$____ properties
- *
- * Loop operations are optimized by using while(count--) { ... }
- * - this means that in order to keep the same order of execution as addition we have to add
- * items to the array at the begging (shift) instead of at the end (push)
- *
- * Child scopes are created and removed often
- * - Using array would be slow since inserts in meddle are expensive so we use linked list
- *
- * There are few watches then a lot of observers. This is why you don't want the observer to be
- * implemented in the same way as watch. Watch requires return of initialization function which
- * are expensive to construct.
- */
-
-
-/**
- * @ngdoc object
- * @name ng.$rootScopeProvider
- * @description
- *
- * Provider for the $rootScope service.
- */
-
-/**
- * @ngdoc function
- * @name ng.$rootScopeProvider#digestTtl
- * @methodOf ng.$rootScopeProvider
- * @description
- *
- * Sets the number of digest iteration the scope should attempt to execute before giving up and
- * assuming that the model is unstable.
- *
- * The current default is 10 iterations.
- *
- * @param {number} limit The number of digest iterations.
- */
-
-
-/**
- * @ngdoc object
- * @name ng.$rootScope
- * @description
- *
- * Every application has a single root {@link ng.$rootScope.Scope scope}.
- * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
- * event processing life-cycle. See {@link guide/scope developer guide on scopes}.
- */
-function $RootScopeProvider(){
- var TTL = 10;
-
- this.digestTtl = function(value) {
- if (arguments.length) {
- TTL = value;
- }
- return TTL;
- };
-
- this.$get = ['$injector', '$exceptionHandler', '$parse',
- function( $injector, $exceptionHandler, $parse) {
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope
- *
- * @description
- * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
- * {@link AUTO.$injector $injector}. Child scopes are created using the
- * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
- * compiled HTML template is executed.)
- *
- * Here is a simple scope snippet to show how you can interact with the scope.
- *
- angular.injector(['ng']).invoke(function($rootScope) {
- var scope = $rootScope.$new();
- scope.salutation = 'Hello';
- scope.name = 'World';
-
- expect(scope.greeting).toEqual(undefined);
-
- scope.$watch('name', function() {
- scope.greeting = scope.salutation + ' ' + scope.name + '!';
- }); // initialize the watch
-
- expect(scope.greeting).toEqual(undefined);
- scope.name = 'Misko';
- // still old value, since watches have not been called yet
- expect(scope.greeting).toEqual(undefined);
-
- scope.$digest(); // fire all the watches
- expect(scope.greeting).toEqual('Hello Misko!');
- });
- *
- *
- * # Inheritance
- * A scope can inherit from a parent scope, as in this example:
- *
- var parent = $rootScope;
- var child = parent.$new();
-
- parent.salutation = "Hello";
- child.name = "World";
- expect(child.salutation).toEqual('Hello');
-
- child.salutation = "Welcome";
- expect(child.salutation).toEqual('Welcome');
- expect(parent.salutation).toEqual('Hello');
- *
- *
- *
- * @param {Object.=} providers Map of service factory which need to be provided
- * for the current scope. Defaults to {@link ng}.
- * @param {Object.=} instanceCache Provides pre-instantiated services which should
- * append/override services provided by `providers`. This is handy when unit-testing and having
- * the need to override a default service.
- * @returns {Object} Newly created scope.
- *
- */
- function Scope() {
- this.$id = nextUid();
- this.$$phase = this.$parent = this.$$watchers =
- this.$$nextSibling = this.$$prevSibling =
- this.$$childHead = this.$$childTail = null;
- this['this'] = this.$root = this;
- this.$$destroyed = false;
- this.$$asyncQueue = [];
- this.$$listeners = {};
- this.$$isolateBindings = {};
- }
-
- /**
- * @ngdoc property
- * @name ng.$rootScope.Scope#$id
- * @propertyOf ng.$rootScope.Scope
- * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
- * debugging.
- */
-
-
- Scope.prototype = {
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$new
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Creates a new child {@link ng.$rootScope.Scope scope}.
- *
- * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
- * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
- * hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
- *
- * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
- * the scope and its child scopes to be permanently detached from the parent and thus stop
- * participating in model change detection and listener notification by invoking.
- *
- * @param {boolean} isolate if true then the scope does not prototypically inherit from the
- * parent scope. The scope is isolated, as it can not see parent scope properties.
- * When creating widgets it is useful for the widget to not accidentally read parent
- * state.
- *
- * @returns {Object} The newly created child scope.
- *
- */
- $new: function(isolate) {
- var Child,
- child;
-
- if (isFunction(isolate)) {
- // TODO: remove at some point
- throw Error('API-CHANGE: Use $controller to instantiate controllers.');
- }
- if (isolate) {
- child = new Scope();
- child.$root = this.$root;
- } else {
- Child = function() {}; // should be anonymous; This is so that when the minifier munges
- // the name it does not become random set of chars. These will then show up as class
- // name in the debugger.
- Child.prototype = this;
- child = new Child();
- child.$id = nextUid();
- }
- child['this'] = child;
- child.$$listeners = {};
- child.$parent = this;
- child.$$asyncQueue = [];
- child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
- child.$$prevSibling = this.$$childTail;
- if (this.$$childHead) {
- this.$$childTail.$$nextSibling = child;
- this.$$childTail = child;
- } else {
- this.$$childHead = this.$$childTail = child;
- }
- return child;
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$watch
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
- *
- * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest $digest()} and
- * should return the value which will be watched. (Since {@link ng.$rootScope.Scope#$digest $digest()}
- * reruns when it detects changes the `watchExpression` can execute multiple times per
- * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
- * - The `listener` is called only when the value from the current `watchExpression` and the
- * previous call to `watchExpression` are not equal (with the exception of the initial run,
- * see below). The inequality is determined according to
- * {@link angular.equals} function. To save the value of the object for later comparison, the
- * {@link angular.copy} function is used. It also means that watching complex options will
- * have adverse memory and performance implications.
- * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
- * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
- * limit is 10 to prevent an infinite loop deadlock.
- *
- *
- * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
- * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
- * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
- * detected, be prepared for multiple calls to your listener.)
- *
- * After a watcher is registered with the scope, the `listener` fn is called asynchronously
- * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
- * watcher. In rare cases, this is undesirable because the listener is called when the result
- * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
- * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
- * listener was called due to initialization.
- *
- *
- * # Example
- *
- // let's assume that scope was dependency injected as the $rootScope
- var scope = $rootScope;
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
- *
- *
- *
- *
- * @param {(function()|string)} watchExpression Expression that is evaluated on each
- * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
- * call to the `listener`.
- *
- * - `string`: Evaluated as {@link guide/expression expression}
- * - `function(scope)`: called with current `scope` as a parameter.
- * @param {(function()|string)=} listener Callback called whenever the return value of
- * the `watchExpression` changes.
- *
- * - `string`: Evaluated as {@link guide/expression expression}
- * - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
- *
- * @param {boolean=} objectEquality Compare object for equality rather than for reference.
- * @returns {function()} Returns a deregistration function for this listener.
- */
- $watch: function(watchExp, listener, objectEquality) {
- var scope = this,
- get = compileToFn(watchExp, 'watch'),
- array = scope.$$watchers,
- watcher = {
- fn: listener,
- last: initWatchVal,
- get: get,
- exp: watchExp,
- eq: !!objectEquality
- };
-
- // in the case user pass string, we need to compile it, do we really need this ?
- if (!isFunction(listener)) {
- var listenFn = compileToFn(listener || noop, 'listener');
- watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
- }
-
- if (!array) {
- array = scope.$$watchers = [];
- }
- // we use unshift since we use a while loop in $digest for speed.
- // the while loop reads in reverse order.
- array.unshift(watcher);
-
- return function() {
- arrayRemove(array, watcher);
- };
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$digest
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
- * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
- * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
- * firing. This means that it is possible to get into an infinite loop. This function will throw
- * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
- *
- * Usually you don't call `$digest()` directly in
- * {@link ng.directive:ngController controllers} or in
- * {@link ng.$compileProvider#directive directives}.
- * Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
- * {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
- *
- * If you want to be notified whenever `$digest()` is called,
- * you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
- * with no `listener`.
- *
- * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
- * life-cycle.
- *
- * # Example
- *
- var scope = ...;
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(newValue, oldValue) {
- scope.counter = scope.counter + 1;
- });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
- *
- *
- */
- $digest: function() {
- var watch, value, last,
- watchers,
- asyncQueue,
- length,
- dirty, ttl = TTL,
- next, current, target = this,
- watchLog = [],
- logIdx, logMsg;
-
- beginPhase('$digest');
-
- do {
- dirty = false;
- current = target;
- do {
- asyncQueue = current.$$asyncQueue;
- while(asyncQueue.length) {
- try {
- current.$eval(asyncQueue.shift());
- } catch (e) {
- $exceptionHandler(e);
- }
- }
- if ((watchers = current.$$watchers)) {
- // process our watches
- length = watchers.length;
- while (length--) {
- try {
- watch = watchers[length];
- // Most common watches are on primitives, in which case we can short
- // circuit it with === operator, only when === fails do we use .equals
- if ((value = watch.get(current)) !== (last = watch.last) &&
- !(watch.eq
- ? equals(value, last)
- : (typeof value == 'number' && typeof last == 'number'
- && isNaN(value) && isNaN(last)))) {
- dirty = true;
- watch.last = watch.eq ? copy(value) : value;
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
- if (ttl < 5) {
- logIdx = 4 - ttl;
- if (!watchLog[logIdx]) watchLog[logIdx] = [];
- logMsg = (isFunction(watch.exp))
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
- : watch.exp;
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
- watchLog[logIdx].push(logMsg);
- }
- }
- } catch (e) {
- $exceptionHandler(e);
- }
- }
- }
-
- // Insanity Warning: scope depth-first traversal
- // yes, this code is a bit crazy, but it works and we have tests to prove it!
- // this piece should be kept in sync with the traversal in $broadcast
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
- current = current.$parent;
- }
- }
- } while ((current = next));
-
- if(dirty && !(ttl--)) {
- clearPhase();
- throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
- 'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
- }
- } while (dirty || asyncQueue.length);
-
- clearPhase();
- },
-
-
- /**
- * @ngdoc event
- * @name ng.$rootScope.Scope#$destroy
- * @eventOf ng.$rootScope.Scope
- * @eventType broadcast on scope being destroyed
- *
- * @description
- * Broadcasted when a scope and its children are being destroyed.
- */
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$destroy
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Removes the current scope (and all of its children) from the parent scope. Removal implies
- * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
- * propagate to the current scope and its children. Removal also implies that the current
- * scope is eligible for garbage collection.
- *
- * The `$destroy()` is usually used by directives such as
- * {@link ng.directive:ngRepeat ngRepeat} for managing the
- * unrolling of the loop.
- *
- * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
- * Application code can register a `$destroy` event handler that will give it chance to
- * perform any necessary cleanup.
- */
- $destroy: function() {
- // we can't destroy the root scope or a scope that has been already destroyed
- if ($rootScope == this || this.$$destroyed) return;
- var parent = this.$parent;
-
- this.$broadcast('$destroy');
- this.$$destroyed = true;
-
- if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
- if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
- if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
- if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
-
- // This is bogus code that works around Chrome's GC leak
- // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
- this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
- this.$$childTail = null;
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$eval
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Executes the `expression` on the current scope returning the result. Any exceptions in the
- * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
- *
- * # Example
- *
- var scope = ng.$rootScope.Scope();
- scope.a = 1;
- scope.b = 2;
-
- expect(scope.$eval('a+b')).toEqual(3);
- expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
- *
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $eval: function(expr, locals) {
- return $parse(expr)(this, locals);
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$evalAsync
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Executes the expression on the current scope at a later point in time.
- *
- * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
- *
- * - it will execute in the current script execution context (before any DOM rendering).
- * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
- * `expression` execution.
- *
- * Any exceptions from the execution of the expression are forwarded to the
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- */
- $evalAsync: function(expr) {
- this.$$asyncQueue.push(expr);
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$apply
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * `$apply()` is used to execute an expression in angular from outside of the angular framework.
- * (For example from browser DOM events, setTimeout, XHR or third party libraries).
- * Because we are calling into the angular framework we need to perform proper scope life-cycle
- * of {@link ng.$exceptionHandler exception handling},
- * {@link ng.$rootScope.Scope#$digest executing watches}.
- *
- * ## Life cycle
- *
- * # Pseudo-Code of `$apply()`
- *
- function $apply(expr) {
- try {
- return $eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- $root.$digest();
- }
- }
- *
- *
- *
- * Scope's `$apply()` method transitions through the following stages:
- *
- * 1. The {@link guide/expression expression} is executed using the
- * {@link ng.$rootScope.Scope#$eval $eval()} method.
- * 2. Any exceptions from the execution of the expression are forwarded to the
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
- * was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
- *
- *
- * @param {(string|function())=} exp An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with current `scope` parameter.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $apply: function(expr) {
- try {
- beginPhase('$apply');
- return this.$eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- clearPhase();
- try {
- $rootScope.$digest();
- } catch (e) {
- $exceptionHandler(e);
- throw e;
- }
- }
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$on
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
- * event life cycle.
- *
- * The event listener function format is: `function(event, args...)`. The `event` object
- * passed into the listener has the following attributes:
- *
- * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
- * - `currentScope` - `{Scope}`: the current scope which is handling the event.
- * - `name` - `{string}`: Name of the event.
- * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
- * propagation (available only for events that were `$emit`-ed).
- * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
- * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
- *
- * @param {string} name Event name to listen on.
- * @param {function(event, args...)} listener Function to call when the event is emitted.
- * @returns {function()} Returns a deregistration function for this listener.
- */
- $on: function(name, listener) {
- var namedListeners = this.$$listeners[name];
- if (!namedListeners) {
- this.$$listeners[name] = namedListeners = [];
- }
- namedListeners.push(listener);
-
- return function() {
- namedListeners[indexOf(namedListeners, listener)] = null;
- };
- },
-
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$emit
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Dispatches an event `name` upwards through the scope hierarchy notifying the
- * registered {@link ng.$rootScope.Scope#$on} listeners.
- *
- * The event life cycle starts at the scope on which `$emit` was called. All
- * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
- * Afterwards, the event traverses upwards toward the root scope and calls all registered
- * listeners along the way. The event will stop propagating if one of the listeners cancels it.
- *
- * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
- * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to emit.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
- */
- $emit: function(name, args) {
- var empty = [],
- namedListeners,
- scope = this,
- stopPropagation = false,
- event = {
- name: name,
- targetScope: scope,
- stopPropagation: function() {stopPropagation = true;},
- preventDefault: function() {
- event.defaultPrevented = true;
- },
- defaultPrevented: false
- },
- listenerArgs = concat([event], arguments, 1),
- i, length;
-
- do {
- namedListeners = scope.$$listeners[name] || empty;
- event.currentScope = scope;
- for (i=0, length=namedListeners.length; i 7),
- hasEvent: function(event) {
- // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
- // it. In particular the event is not fired when backspace or delete key are pressed or
- // when cut operation is performed.
- if (event == 'input' && msie == 9) return false;
-
- if (isUndefined(eventSupport[event])) {
- var divElm = $window.document.createElement('div');
- eventSupport[event] = 'on' + event in divElm;
- }
-
- return eventSupport[event];
- },
- // TODO(i): currently there is no way to feature detect CSP without triggering alerts
- csp: false
- };
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$window
- *
- * @description
- * A reference to the browser's `window` object. While `window`
- * is globally available in JavaScript, it causes testability problems, because
- * it is a global variable. In angular we always refer to it through the
- * `$window` service, so it may be overriden, removed or mocked for testing.
- *
- * All expressions are evaluated with respect to current scope so they don't
- * suffer from window globality.
- *
- * @example
-
-
-
- ALERT
-
-
-
-
- */
-function $WindowProvider(){
- this.$get = valueFn(window);
-}
-
-/**
- * Parse headers into key value object
- *
- * @param {string} headers Raw headers as a string
- * @returns {Object} Parsed headers as key value object
- */
-function parseHeaders(headers) {
- var parsed = {}, key, val, i;
-
- if (!headers) return parsed;
-
- forEach(headers.split('\n'), function(line) {
- i = line.indexOf(':');
- key = lowercase(trim(line.substr(0, i)));
- val = trim(line.substr(i + 1));
-
- if (key) {
- if (parsed[key]) {
- parsed[key] += ', ' + val;
- } else {
- parsed[key] = val;
- }
- }
- });
-
- return parsed;
-}
-
-
-/**
- * Returns a function that provides access to parsed headers.
- *
- * Headers are lazy parsed when first requested.
- * @see parseHeaders
- *
- * @param {(string|Object)} headers Headers to provide access to.
- * @returns {function(string=)} Returns a getter function which if called with:
- *
- * - if called with single an argument returns a single header value or null
- * - if called with no arguments returns an object containing all headers.
- */
-function headersGetter(headers) {
- var headersObj = isObject(headers) ? headers : undefined;
-
- return function(name) {
- if (!headersObj) headersObj = parseHeaders(headers);
-
- if (name) {
- return headersObj[lowercase(name)] || null;
- }
-
- return headersObj;
- };
-}
-
-
-/**
- * Chain all given functions
- *
- * This function is used for both request and response transforming
- *
- * @param {*} data Data to transform.
- * @param {function(string=)} headers Http headers getter fn.
- * @param {(function|Array.)} fns Function or an array of functions.
- * @returns {*} Transformed data.
- */
-function transformData(data, headers, fns) {
- if (isFunction(fns))
- return fns(data, headers);
-
- forEach(fns, function(fn) {
- data = fn(data, headers);
- });
-
- return data;
-}
-
-
-function isSuccess(status) {
- return 200 <= status && status < 300;
-}
-
-
-function $HttpProvider() {
- var JSON_START = /^\s*(\[|\{[^\{])/,
- JSON_END = /[\}\]]\s*$/,
- PROTECTION_PREFIX = /^\)\]\}',?\n/;
-
- var $config = this.defaults = {
- // transform incoming response data
- transformResponse: [function(data) {
- if (isString(data)) {
- // strip json vulnerability protection prefix
- data = data.replace(PROTECTION_PREFIX, '');
- if (JSON_START.test(data) && JSON_END.test(data))
- data = fromJson(data, true);
- }
- return data;
- }],
-
- // transform outgoing request data
- transformRequest: [function(d) {
- return isObject(d) && !isFile(d) ? toJson(d) : d;
- }],
-
- // default headers
- headers: {
- common: {
- 'Accept': 'application/json, text/plain, */*',
- 'X-Requested-With': 'XMLHttpRequest'
- },
- post: {'Content-Type': 'application/json;charset=utf-8'},
- put: {'Content-Type': 'application/json;charset=utf-8'}
- }
- };
-
- var providerResponseInterceptors = this.responseInterceptors = [];
-
- this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
- function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
-
- var defaultCache = $cacheFactory('$http'),
- responseInterceptors = [];
-
- forEach(providerResponseInterceptors, function(interceptor) {
- responseInterceptors.push(
- isString(interceptor)
- ? $injector.get(interceptor)
- : $injector.invoke(interceptor)
- );
- });
-
-
- /**
- * @ngdoc function
- * @name ng.$http
- * @requires $httpBackend
- * @requires $browser
- * @requires $cacheFactory
- * @requires $rootScope
- * @requires $q
- * @requires $injector
- *
- * @description
- * The `$http` service is a core Angular service that facilitates communication with the remote
- * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
- * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
- *
- * For unit testing applications that use `$http` service, see
- * {@link ngMock.$httpBackend $httpBackend mock}.
- *
- * For a higher level of abstraction, please check out the {@link ngResource.$resource
- * $resource} service.
- *
- * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
- * the $q service. While for simple usage patters this doesn't matter much, for advanced usage,
- * it is important to familiarize yourself with these apis and guarantees they provide.
- *
- *
- * # General usage
- * The `$http` service is a function which takes a single argument — a configuration object —
- * that is used to generate an http request and returns a {@link ng.$q promise}
- * with two $http specific methods: `success` and `error`.
- *
- *
- * $http({method: 'GET', url: '/someUrl'}).
- * success(function(data, status, headers, config) {
- * // this callback will be called asynchronously
- * // when the response is available
- * }).
- * error(function(data, status, headers, config) {
- * // called asynchronously if an error occurs
- * // or server returns response with an error status.
- * });
- *
- *
- * Since the returned value of calling the $http function is a Promise object, you can also use
- * the `then` method to register callbacks, and these callbacks will receive a single argument –
- * an object representing the response. See the api signature and type info below for more
- * details.
- *
- * A response status code that falls in the [200, 300) range is considered a success status and
- * will result in the success callback being called. Note that if the response is a redirect,
- * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
- * called for such responses.
- *
- * # Shortcut methods
- *
- * Since all invocation of the $http service require definition of the http method and url and
- * POST and PUT requests require response body/data to be provided as well, shortcut methods
- * were created to simplify using the api:
- *
- *
- * $http.get('/someUrl').success(successCallback);
- * $http.post('/someUrl', data).success(successCallback);
- *
- *
- * Complete list of shortcut methods:
- *
- * - {@link ng.$http#get $http.get}
- * - {@link ng.$http#head $http.head}
- * - {@link ng.$http#post $http.post}
- * - {@link ng.$http#put $http.put}
- * - {@link ng.$http#delete $http.delete}
- * - {@link ng.$http#jsonp $http.jsonp}
- *
- *
- * # Setting HTTP Headers
- *
- * The $http service will automatically add certain http headers to all requests. These defaults
- * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
- * object, which currently contains this default configuration:
- *
- * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
- * - `Accept: application/json, text/plain, * / *`
- * - `X-Requested-With: XMLHttpRequest`
- * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
- * - `Content-Type: application/json`
- * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
- * - `Content-Type: application/json`
- *
- * To add or overwrite these defaults, simply add or remove a property from this configuration
- * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
- * with name equal to the lower-cased http method name, e.g.
- * `$httpProvider.defaults.headers.get['My-Header']='value'`.
- *
- * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
- * fassion as described above.
- *
- *
- * # Transforming Requests and Responses
- *
- * Both requests and responses can be transformed using transform functions. By default, Angular
- * applies these transformations:
- *
- * Request transformations:
- *
- * - if the `data` property of the request config object contains an object, serialize it into
- * JSON format.
- *
- * Response transformations:
- *
- * - if XSRF prefix is detected, strip it (see Security Considerations section below)
- * - if json response is detected, deserialize it using a JSON parser
- *
- * To override these transformation locally, specify transform functions as `transformRequest`
- * and/or `transformResponse` properties of the config object. To globally override the default
- * transforms, override the `$httpProvider.defaults.transformRequest` and
- * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
- *
- *
- * # Caching
- *
- * To enable caching set the configuration property `cache` to `true`. When the cache is
- * enabled, `$http` stores the response from the server in local cache. Next time the
- * response is served from the cache without sending a request to the server.
- *
- * Note that even if the response is served from cache, delivery of the data is asynchronous in
- * the same way that real requests are.
- *
- * If there are multiple GET requests for the same url that should be cached using the same
- * cache, but the cache is not populated yet, only one request to the server will be made and
- * the remaining requests will be fulfilled using the response for the first request.
- *
- *
- * # Response interceptors
- *
- * Before you start creating interceptors, be sure to understand the
- * {@link ng.$q $q and deferred/promise APIs}.
- *
- * For purposes of global error handling, authentication or any kind of synchronous or
- * asynchronous preprocessing of received responses, it is desirable to be able to intercept
- * responses for http requests before they are handed over to the application code that
- * initiated these requests. The response interceptors leverage the {@link ng.$q
- * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
- *
- * The interceptors are service factories that are registered with the $httpProvider by
- * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
- * injected with dependencies (if specified) and returns the interceptor — a function that
- * takes a {@link ng.$q promise} and returns the original or a new promise.
- *
- *
- * // register the interceptor as a service
- * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
- * return function(promise) {
- * return promise.then(function(response) {
- * // do something on success
- * }, function(response) {
- * // do something on error
- * if (canRecover(response)) {
- * return responseOrNewPromise
- * }
- * return $q.reject(response);
- * });
- * }
- * });
- *
- * $httpProvider.responseInterceptors.push('myHttpInterceptor');
- *
- *
- * // register the interceptor via an anonymous factory
- * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
- * return function(promise) {
- * // same as above
- * }
- * });
- *
- *
- *
- * # Security Considerations
- *
- * When designing web applications, consider security threats from:
- *
- * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON Vulnerability}
- * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
- *
- * Both server and the client must cooperate in order to eliminate these threats. Angular comes
- * pre-configured with strategies that address these issues, but for this to work backend server
- * cooperation is required.
- *
- * ## JSON Vulnerability Protection
- *
- * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
- * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
- * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
- * Angular will automatically strip the prefix before processing it as JSON.
- *
- * For example if your server needs to return:
- *
- * ['one','two']
- *
- *
- * which is vulnerable to attack, your server can return:
- *
- * )]}',
- * ['one','two']
- *
- *
- * Angular will strip the prefix, before processing the JSON.
- *
- *
- * ## Cross Site Request Forgery (XSRF) Protection
- *
- * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
- * an unauthorized site can gain your user's private data. Angular provides following mechanism
- * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
- * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
- * runs on your domain could read the cookie, your server can be assured that the XHR came from
- * JavaScript running on your domain.
- *
- * To take advantage of this, your server needs to set a token in a JavaScript readable session
- * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
- * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
- * that only JavaScript running on your domain could have read the token. The token must be
- * unique for each user and must be verifiable by the server (to prevent the JavaScript making
- * up its own tokens). We recommend that the token is a digest of your site's authentication
- * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
- *
- *
- * @param {object} config Object describing the request to be made and how it should be
- * processed. The object has following properties:
- *
- * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
- * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
- * - **params** – `{Object.}` – Map of strings or objects which will be turned to
- * `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
- * - **data** – `{string|Object}` – Data to be sent as the request message data.
- * - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server.
- * - **transformRequest** – `{function(data, headersGetter)|Array.}` –
- * transform function or an array of such functions. The transform function takes the http
- * request body and headers and returns its transformed (typically serialized) version.
- * - **transformResponse** – `{function(data, headersGetter)|Array.}` –
- * transform function or an array of such functions. The transform function takes the http
- * response body and headers and returns its transformed (typically deserialized) version.
- * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
- * GET request, otherwise if a cache instance built with
- * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
- * caching.
- * - **timeout** – `{number}` – timeout in milliseconds.
- * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
- * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
- * requests with credentials} for more information.
- *
- * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
- * standard `then` method and two http specific methods: `success` and `error`. The `then`
- * method takes two arguments a success and an error callback which will be called with a
- * response object. The `success` and `error` methods take a single argument - a function that
- * will be called when the request succeeds or fails respectively. The arguments passed into
- * these functions are destructured representation of the response object passed into the
- * `then` method. The response object has these properties:
- *
- * - **data** – `{string|Object}` – The response body transformed with the transform functions.
- * - **status** – `{number}` – HTTP status code of the response.
- * - **headers** – `{function([headerName])}` – Header getter function.
- * - **config** – `{Object}` – The configuration object that was used to generate the request.
- *
- * @property {Array.} pendingRequests Array of config objects for currently pending
- * requests. This is primarily meant to be used for debugging purposes.
- *
- *
- * @example
-
-
-
-
- GET
- JSONP
-
-
-
fetch
-
Sample GET
-
Sample JSONP
-
Invalid JSONP
-
http status code: {{status}}
-
http response data: {{data}}
-
-
-
- function FetchCtrl($scope, $http, $templateCache) {
- $scope.method = 'GET';
- $scope.url = 'http-hello.html';
-
- $scope.fetch = function() {
- $scope.code = null;
- $scope.response = null;
-
- $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
- success(function(data, status) {
- $scope.status = status;
- $scope.data = data;
- }).
- error(function(data, status) {
- $scope.data = data || "Request failed";
- $scope.status = status;
- });
- };
-
- $scope.updateModel = function(method, url) {
- $scope.method = method;
- $scope.url = url;
- };
- }
-
-
- Hello, $http!
-
-
- it('should make an xhr GET request', function() {
- element(':button:contains("Sample GET")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Hello, \$http!/);
- });
-
- it('should make a JSONP request to angularjs.org', function() {
- element(':button:contains("Sample JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Super Hero!/);
- });
-
- it('should make JSONP request to invalid URL and invoke the error handler',
- function() {
- element(':button:contains("Invalid JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('0');
- expect(binding('data')).toBe('Request failed');
- });
-
-
- */
- function $http(config) {
- config.method = uppercase(config.method);
-
- var reqTransformFn = config.transformRequest || $config.transformRequest,
- respTransformFn = config.transformResponse || $config.transformResponse,
- defHeaders = $config.headers,
- reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
- defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
- reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
- promise;
-
- // strip content-type if data is undefined
- if (isUndefined(config.data)) {
- delete reqHeaders['Content-Type'];
- }
-
- // send request
- promise = sendReq(config, reqData, reqHeaders);
-
-
- // transform future response
- promise = promise.then(transformResponse, transformResponse);
-
- // apply interceptors
- forEach(responseInterceptors, function(interceptor) {
- promise = interceptor(promise);
- });
-
- promise.success = function(fn) {
- promise.then(function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
-
- promise.error = function(fn) {
- promise.then(null, function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
-
- return promise;
-
- function transformResponse(response) {
- // make a copy since the response must be cacheable
- var resp = extend({}, response, {
- data: transformData(response.data, response.headers, respTransformFn)
- });
- return (isSuccess(response.status))
- ? resp
- : $q.reject(resp);
- }
- }
-
- $http.pendingRequests = [];
-
- /**
- * @ngdoc method
- * @name ng.$http#get
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `GET` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#delete
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `DELETE` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#head
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `HEAD` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#jsonp
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `JSONP` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request.
- * Should contain `JSON_CALLBACK` string.
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
- createShortMethods('get', 'delete', 'head', 'jsonp');
-
- /**
- * @ngdoc method
- * @name ng.$http#post
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `POST` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {*} data Request content
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#put
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `PUT` request
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {*} data Request content
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
- createShortMethodsWithData('post', 'put');
-
- /**
- * @ngdoc property
- * @name ng.$http#defaults
- * @propertyOf ng.$http
- *
- * @description
- * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
- * default headers as well as request and response transformations.
- *
- * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
- */
- $http.defaults = $config;
-
-
- return $http;
-
-
- function createShortMethods(names) {
- forEach(arguments, function(name) {
- $http[name] = function(url, config) {
- return $http(extend(config || {}, {
- method: name,
- url: url
- }));
- };
- });
- }
-
-
- function createShortMethodsWithData(name) {
- forEach(arguments, function(name) {
- $http[name] = function(url, data, config) {
- return $http(extend(config || {}, {
- method: name,
- url: url,
- data: data
- }));
- };
- });
- }
-
-
- /**
- * Makes the request
- *
- * !!! ACCESSES CLOSURE VARS:
- * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
- */
- function sendReq(config, reqData, reqHeaders) {
- var deferred = $q.defer(),
- promise = deferred.promise,
- cache,
- cachedResp,
- url = buildUrl(config.url, config.params);
-
- $http.pendingRequests.push(config);
- promise.then(removePendingReq, removePendingReq);
-
-
- if (config.cache && config.method == 'GET') {
- cache = isObject(config.cache) ? config.cache : defaultCache;
- }
-
- if (cache) {
- cachedResp = cache.get(url);
- if (cachedResp) {
- if (cachedResp.then) {
- // cached request has already been sent, but there is no response yet
- cachedResp.then(removePendingReq, removePendingReq);
- return cachedResp;
- } else {
- // serving from cache
- if (isArray(cachedResp)) {
- resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
- } else {
- resolvePromise(cachedResp, 200, {});
- }
- }
- } else {
- // put the promise for the non-transformed response into cache as a placeholder
- cache.put(url, promise);
- }
- }
-
- // if we won't have the response in cache, send the request to the backend
- if (!cachedResp) {
- $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
- config.withCredentials);
- }
-
- return promise;
-
-
- /**
- * Callback registered to $httpBackend():
- * - caches the response if desired
- * - resolves the raw $http promise
- * - calls $apply
- */
- function done(status, response, headersString) {
- if (cache) {
- if (isSuccess(status)) {
- cache.put(url, [status, response, parseHeaders(headersString)]);
- } else {
- // remove promise from the cache
- cache.remove(url);
- }
- }
-
- resolvePromise(response, status, headersString);
- $rootScope.$apply();
- }
-
-
- /**
- * Resolves the raw $http promise.
- */
- function resolvePromise(response, status, headers) {
- // normalize internal statuses to 0
- status = Math.max(status, 0);
-
- (isSuccess(status) ? deferred.resolve : deferred.reject)({
- data: response,
- status: status,
- headers: headersGetter(headers),
- config: config
- });
- }
-
-
- function removePendingReq() {
- var idx = indexOf($http.pendingRequests, config);
- if (idx !== -1) $http.pendingRequests.splice(idx, 1);
- }
- }
-
-
- function buildUrl(url, params) {
- if (!params) return url;
- var parts = [];
- forEachSorted(params, function(value, key) {
- if (value == null || value == undefined) return;
- if (isObject(value)) {
- value = toJson(value);
- }
- parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
- });
- return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
- }
-
-
- }];
-}
-var XHR = window.XMLHttpRequest || function() {
- try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
- try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
- try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
- throw new Error("This browser does not support XMLHttpRequest.");
-};
-
-
-/**
- * @ngdoc object
- * @name ng.$httpBackend
- * @requires $browser
- * @requires $window
- * @requires $document
- *
- * @description
- * HTTP backend used by the {@link ng.$http service} that delegates to
- * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
- *
- * You should never need to use this service directly, instead use the higher-level abstractions:
- * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
- *
- * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
- * $httpBackend} which can be trained with responses.
- */
-function $HttpBackendProvider() {
- this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
- return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
- $document[0], $window.location.protocol.replace(':', ''));
- }];
-}
-
-function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
- // TODO(vojta): fix the signature
- return function(method, url, post, callback, headers, timeout, withCredentials) {
- $browser.$$incOutstandingRequestCount();
- url = url || $browser.url();
-
- if (lowercase(method) == 'jsonp') {
- var callbackId = '_' + (callbacks.counter++).toString(36);
- callbacks[callbackId] = function(data) {
- callbacks[callbackId].data = data;
- };
-
- jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
- function() {
- if (callbacks[callbackId].data) {
- completeRequest(callback, 200, callbacks[callbackId].data);
- } else {
- completeRequest(callback, -2);
- }
- delete callbacks[callbackId];
- });
- } else {
- var xhr = new XHR();
- xhr.open(method, url, true);
- forEach(headers, function(value, key) {
- if (value) xhr.setRequestHeader(key, value);
- });
-
- var status;
-
- // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
- // response is in the cache. the promise api will ensure that to the app code the api is
- // always async
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- var responseHeaders = xhr.getAllResponseHeaders();
-
- // TODO(vojta): remove once Firefox 21 gets released.
- // begin: workaround to overcome Firefox CORS http response headers bug
- // https://bugzilla.mozilla.org/show_bug.cgi?id=608735
- // Firefox already patched in nightly. Should land in Firefox 21.
-
- // CORS "simple response headers" http://www.w3.org/TR/cors/
- var value,
- simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
- "Expires", "Last-Modified", "Pragma"];
- if (!responseHeaders) {
- responseHeaders = "";
- forEach(simpleHeaders, function (header) {
- var value = xhr.getResponseHeader(header);
- if (value) {
- responseHeaders += header + ": " + value + "\n";
- }
- });
- }
- // end of the workaround.
-
- completeRequest(callback, status || xhr.status, xhr.responseText,
- responseHeaders);
- }
- };
-
- if (withCredentials) {
- xhr.withCredentials = true;
- }
-
- xhr.send(post || '');
-
- if (timeout > 0) {
- $browserDefer(function() {
- status = -1;
- xhr.abort();
- }, timeout);
- }
- }
-
-
- function completeRequest(callback, status, response, headersString) {
- // URL_MATCH is defined in src/service/location.js
- var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1];
-
- // fix status code for file protocol (it's always 0)
- status = (protocol == 'file') ? (response ? 200 : 404) : status;
-
- // normalize IE bug (http://bugs.jquery.com/ticket/1450)
- status = status == 1223 ? 204 : status;
-
- callback(status, response, headersString);
- $browser.$$completeOutstandingRequest(noop);
- }
- };
-
- function jsonpReq(url, done) {
- // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
- // - fetches local scripts via XHR and evals them
- // - adds and immediately removes script elements from the document
- var script = rawDocument.createElement('script'),
- doneWrapper = function() {
- rawDocument.body.removeChild(script);
- if (done) done();
- };
-
- script.type = 'text/javascript';
- script.src = url;
-
- if (msie) {
- script.onreadystatechange = function() {
- if (/loaded|complete/.test(script.readyState)) doneWrapper();
- };
- } else {
- script.onload = script.onerror = doneWrapper;
- }
-
- rawDocument.body.appendChild(script);
- }
-}
-
-/**
- * @ngdoc object
- * @name ng.$locale
- *
- * @description
- * $locale service provides localization rules for various Angular components. As of right now the
- * only public api is:
- *
- * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
- */
-function $LocaleProvider(){
- this.$get = function() {
- return {
- id: 'en-us',
-
- NUMBER_FORMATS: {
- DECIMAL_SEP: '.',
- GROUP_SEP: ',',
- PATTERNS: [
- { // Decimal Pattern
- minInt: 1,
- minFrac: 0,
- maxFrac: 3,
- posPre: '',
- posSuf: '',
- negPre: '-',
- negSuf: '',
- gSize: 3,
- lgSize: 3
- },{ //Currency Pattern
- minInt: 1,
- minFrac: 2,
- maxFrac: 2,
- posPre: '\u00A4',
- posSuf: '',
- negPre: '(\u00A4',
- negSuf: ')',
- gSize: 3,
- lgSize: 3
- }
- ],
- CURRENCY_SYM: '$'
- },
-
- DATETIME_FORMATS: {
- MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
- .split(','),
- SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
- DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
- SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
- AMPMS: ['AM','PM'],
- medium: 'MMM d, y h:mm:ss a',
- short: 'M/d/yy h:mm a',
- fullDate: 'EEEE, MMMM d, y',
- longDate: 'MMMM d, y',
- mediumDate: 'MMM d, y',
- shortDate: 'M/d/yy',
- mediumTime: 'h:mm:ss a',
- shortTime: 'h:mm a'
- },
-
- pluralCat: function(num) {
- if (num === 1) {
- return 'one';
- }
- return 'other';
- }
- };
- };
-}
-
-function $TimeoutProvider() {
- this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
- function($rootScope, $browser, $q, $exceptionHandler) {
- var deferreds = {};
-
-
- /**
- * @ngdoc function
- * @name ng.$timeout
- * @requires $browser
- *
- * @description
- * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
- * block and delegates any exceptions to
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * The return value of registering a timeout function is a promise which will be resolved when
- * the timeout is reached and the timeout function is executed.
- *
- * To cancel a the timeout request, call `$timeout.cancel(promise)`.
- *
- * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
- * synchronously flush the queue of deferred functions.
- *
- * @param {function()} fn A function, who's execution should be delayed.
- * @param {number=} [delay=0] Delay in milliseconds.
- * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
- * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
- * promise will be resolved with is the return value of the `fn` function.
- */
- function timeout(fn, delay, invokeApply) {
- var deferred = $q.defer(),
- promise = deferred.promise,
- skipApply = (isDefined(invokeApply) && !invokeApply),
- timeoutId, cleanup;
-
- timeoutId = $browser.defer(function() {
- try {
- deferred.resolve(fn());
- } catch(e) {
- deferred.reject(e);
- $exceptionHandler(e);
- }
-
- if (!skipApply) $rootScope.$apply();
- }, delay);
-
- cleanup = function() {
- delete deferreds[promise.$$timeoutId];
- };
-
- promise.$$timeoutId = timeoutId;
- deferreds[timeoutId] = deferred;
- promise.then(cleanup, cleanup);
-
- return promise;
- }
-
-
- /**
- * @ngdoc function
- * @name ng.$timeout#cancel
- * @methodOf ng.$timeout
- *
- * @description
- * Cancels a task associated with the `promise`. As a result of this the promise will be
- * resolved with a rejection.
- *
- * @param {Promise=} promise Promise returned by the `$timeout` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
- * canceled.
- */
- timeout.cancel = function(promise) {
- if (promise && promise.$$timeoutId in deferreds) {
- deferreds[promise.$$timeoutId].reject('canceled');
- return $browser.defer.cancel(promise.$$timeoutId);
- }
- return false;
- };
-
- return timeout;
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$filterProvider
- * @description
- *
- * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
- * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
- * responsible for creating a the filter function.
- *
- *
- * // Filter registration
- * function MyModule($provide, $filterProvider) {
- * // create a service to demonstrate injection (not always needed)
- * $provide.value('greet', function(name){
- * return 'Hello ' + name + '!';
- * });
- *
- * // register a filter factory which uses the
- * // greet service to demonstrate DI.
- * $filterProvider.register('greet', function(greet){
- * // return the filter function which uses the greet service
- * // to generate salutation
- * return function(text) {
- * // filters need to be forgiving so check input validity
- * return text && greet(text) || text;
- * };
- * });
- * }
- *
- *
- * The filter function is registered with the `$injector` under the filter name suffixe with `Filter`.
- *
- * it('should be the same instance', inject(
- * function($filterProvider) {
- * $filterProvider.register('reverse', function(){
- * return ...;
- * });
- * },
- * function($filter, reverseFilter) {
- * expect($filter('reverse')).toBe(reverseFilter);
- * });
- *
- *
- *
- * For more information about how angular filters work, and how to create your own filters, see
- * {@link guide/dev_guide.templates.filters Understanding Angular Filters} in the angular Developer
- * Guide.
- */
-/**
- * @ngdoc method
- * @name ng.$filterProvider#register
- * @methodOf ng.$filterProvider
- * @description
- * Register filter factory function.
- *
- * @param {String} name Name of the filter.
- * @param {function} fn The filter factory function which is injectable.
- */
-
-
-/**
- * @ngdoc function
- * @name ng.$filter
- * @function
- * @description
- * Filters are used for formatting data displayed to the user.
- *
- * The general syntax in templates is as follows:
- *
- * {{ expression | [ filter_name ] }}
- *
- * @param {String} name Name of the filter function to retrieve
- * @return {Function} the filter function
- */
-$FilterProvider.$inject = ['$provide'];
-function $FilterProvider($provide) {
- var suffix = 'Filter';
-
- function register(name, factory) {
- return $provide.factory(name + suffix, factory);
- }
- this.register = register;
-
- this.$get = ['$injector', function($injector) {
- return function(name) {
- return $injector.get(name + suffix);
- }
- }];
-
- ////////////////////////////////////////
-
- register('currency', currencyFilter);
- register('date', dateFilter);
- register('filter', filterFilter);
- register('json', jsonFilter);
- register('limitTo', limitToFilter);
- register('lowercase', lowercaseFilter);
- register('number', numberFilter);
- register('orderBy', orderByFilter);
- register('uppercase', uppercaseFilter);
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:filter
- * @function
- *
- * @description
- * Selects a subset of items from `array` and returns it as a new array.
- *
- * Note: This function is used to augment the `Array` type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
- * @param {Array} array The source array.
- * @param {string|Object|function()} expression The predicate to be used for selecting items from
- * `array`.
- *
- * Can be one of:
- *
- * - `string`: Predicate that results in a substring match using the value of `expression`
- * string. All strings or objects with string properties in `array` that contain this string
- * will be returned. The predicate can be negated by prefixing the string with `!`.
- *
- * - `Object`: A pattern object can be used to filter specific properties on objects contained
- * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
- * which have property `name` containing "M" and property `phone` containing "1". A special
- * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
- * property of the object. That's equivalent to the simple substring match with a `string`
- * as described above.
- *
- * - `function`: A predicate function can be used to write arbitrary filters. The function is
- * called for each element of `array`. The final result is an array of those elements that
- * the predicate returned true for.
- *
- * @example
-
-
-
-
- Search:
-
- Name Phone
-
- {{friend.name}}
- {{friend.phone}}
-
-
-
- Any:
- Name only
- Phone only
-
- Name Phone
-
- {{friend.name}}
- {{friend.phone}}
-
-
-
-
- it('should search across all fields when filtering with a string', function() {
- input('searchText').enter('m');
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Mike', 'Adam']);
-
- input('searchText').enter('76');
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
- toEqual(['John', 'Julie']);
- });
-
- it('should search in specific fields when filtering with a predicate object', function() {
- input('search.$').enter('i');
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Mike', 'Julie']);
- });
-
-
- */
-function filterFilter() {
- return function(array, expression) {
- if (!isArray(array)) return array;
- var predicates = [];
- predicates.check = function(value) {
- for (var j = 0; j < predicates.length; j++) {
- if(!predicates[j](value)) {
- return false;
- }
- }
- return true;
- };
- var search = function(obj, text){
- if (text.charAt(0) === '!') {
- return !search(obj, text.substr(1));
- }
- switch (typeof obj) {
- case "boolean":
- case "number":
- case "string":
- return ('' + obj).toLowerCase().indexOf(text) > -1;
- case "object":
- for ( var objKey in obj) {
- if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
- return true;
- }
- }
- return false;
- case "array":
- for ( var i = 0; i < obj.length; i++) {
- if (search(obj[i], text)) {
- return true;
- }
- }
- return false;
- default:
- return false;
- }
- };
- switch (typeof expression) {
- case "boolean":
- case "number":
- case "string":
- expression = {$:expression};
- case "object":
- for (var key in expression) {
- if (key == '$') {
- (function() {
- var text = (''+expression[key]).toLowerCase();
- if (!text) return;
- predicates.push(function(value) {
- return search(value, text);
- });
- })();
- } else {
- (function() {
- var path = key;
- var text = (''+expression[key]).toLowerCase();
- if (!text) return;
- predicates.push(function(value) {
- return search(getter(value, path), text);
- });
- })();
- }
- }
- break;
- case 'function':
- predicates.push(expression);
- break;
- default:
- return array;
- }
- var filtered = [];
- for ( var j = 0; j < array.length; j++) {
- var value = array[j];
- if (predicates.check(value)) {
- filtered.push(value);
- }
- }
- return filtered;
- }
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:currency
- * @function
- *
- * @description
- * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
- * symbol for current locale is used.
- *
- * @param {number} amount Input to filter.
- * @param {string=} symbol Currency symbol or identifier to be displayed.
- * @returns {string} Formatted number.
- *
- *
- * @example
-
-
-
-
-
- default currency symbol ($): {{amount | currency}}
- custom currency identifier (USD$): {{amount | currency:"USD$"}}
-
-
-
- it('should init with 1234.56', function() {
- expect(binding('amount | currency')).toBe('$1,234.56');
- expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
- });
- it('should update', function() {
- input('amount').enter('-1234');
- expect(binding('amount | currency')).toBe('($1,234.00)');
- expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
- });
-
-
- */
-currencyFilter.$inject = ['$locale'];
-function currencyFilter($locale) {
- var formats = $locale.NUMBER_FORMATS;
- return function(amount, currencySymbol){
- if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
- return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
- replace(/\u00A4/g, currencySymbol);
- };
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:number
- * @function
- *
- * @description
- * Formats a number as text.
- *
- * If the input is not a number an empty string is returned.
- *
- * @param {number|string} number Number to format.
- * @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
- * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
- *
- * @example
-
-
-
-
- Enter number:
- Default formatting: {{val | number}}
- No fractions: {{val | number:0}}
- Negative number: {{-val | number:4}}
-
-
-
- it('should format numbers', function() {
- expect(binding('val | number')).toBe('1,234.568');
- expect(binding('val | number:0')).toBe('1,235');
- expect(binding('-val | number:4')).toBe('-1,234.5679');
- });
-
- it('should update', function() {
- input('val').enter('3374.333');
- expect(binding('val | number')).toBe('3,374.333');
- expect(binding('val | number:0')).toBe('3,374');
- expect(binding('-val | number:4')).toBe('-3,374.3330');
- });
-
-
- */
-
-
-numberFilter.$inject = ['$locale'];
-function numberFilter($locale) {
- var formats = $locale.NUMBER_FORMATS;
- return function(number, fractionSize) {
- return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
- fractionSize);
- };
-}
-
-var DECIMAL_SEP = '.';
-function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
- if (isNaN(number) || !isFinite(number)) return '';
-
- var isNegative = number < 0;
- number = Math.abs(number);
- var numStr = number + '',
- formatedText = '',
- parts = [];
-
- var hasExponent = false;
- if (numStr.indexOf('e') !== -1) {
- var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
- if (match && match[2] == '-' && match[3] > fractionSize + 1) {
- numStr = '0';
- } else {
- formatedText = numStr;
- hasExponent = true;
- }
- }
-
- if (!hasExponent) {
- var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
-
- // determine fractionSize if it is not specified
- if (isUndefined(fractionSize)) {
- fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
- }
-
- var pow = Math.pow(10, fractionSize);
- number = Math.round(number * pow) / pow;
- var fraction = ('' + number).split(DECIMAL_SEP);
- var whole = fraction[0];
- fraction = fraction[1] || '';
-
- var pos = 0,
- lgroup = pattern.lgSize,
- group = pattern.gSize;
-
- if (whole.length >= (lgroup + group)) {
- pos = whole.length - lgroup;
- for (var i = 0; i < pos; i++) {
- if ((pos - i)%group === 0 && i !== 0) {
- formatedText += groupSep;
- }
- formatedText += whole.charAt(i);
- }
- }
-
- for (i = pos; i < whole.length; i++) {
- if ((whole.length - i)%lgroup === 0 && i !== 0) {
- formatedText += groupSep;
- }
- formatedText += whole.charAt(i);
- }
-
- // format fraction part.
- while(fraction.length < fractionSize) {
- fraction += '0';
- }
-
- if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
- }
-
- parts.push(isNegative ? pattern.negPre : pattern.posPre);
- parts.push(formatedText);
- parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
- return parts.join('');
-}
-
-function padNumber(num, digits, trim) {
- var neg = '';
- if (num < 0) {
- neg = '-';
- num = -num;
- }
- num = '' + num;
- while(num.length < digits) num = '0' + num;
- if (trim)
- num = num.substr(num.length - digits);
- return neg + num;
-}
-
-
-function dateGetter(name, size, offset, trim) {
- return function(date) {
- var value = date['get' + name]();
- if (offset > 0 || value > -offset)
- value += offset;
- if (value === 0 && offset == -12 ) value = 12;
- return padNumber(value, size, trim);
- };
-}
-
-function dateStrGetter(name, shortForm) {
- return function(date, formats) {
- var value = date['get' + name]();
- var get = uppercase(shortForm ? ('SHORT' + name) : name);
-
- return formats[get][value];
- };
-}
-
-function timeZoneGetter(date) {
- var zone = -1 * date.getTimezoneOffset();
- var paddedZone = (zone >= 0) ? "+" : "";
-
- paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2);
-
- return paddedZone;
-}
-
-function ampmGetter(date, formats) {
- return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
-}
-
-var DATE_FORMATS = {
- yyyy: dateGetter('FullYear', 4),
- yy: dateGetter('FullYear', 2, 0, true),
- y: dateGetter('FullYear', 1),
- MMMM: dateStrGetter('Month'),
- MMM: dateStrGetter('Month', true),
- MM: dateGetter('Month', 2, 1),
- M: dateGetter('Month', 1, 1),
- dd: dateGetter('Date', 2),
- d: dateGetter('Date', 1),
- HH: dateGetter('Hours', 2),
- H: dateGetter('Hours', 1),
- hh: dateGetter('Hours', 2, -12),
- h: dateGetter('Hours', 1, -12),
- mm: dateGetter('Minutes', 2),
- m: dateGetter('Minutes', 1),
- ss: dateGetter('Seconds', 2),
- s: dateGetter('Seconds', 1),
- EEEE: dateStrGetter('Day'),
- EEE: dateStrGetter('Day', true),
- a: ampmGetter,
- Z: timeZoneGetter
-};
-
-var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
- NUMBER_STRING = /^\d+$/;
-
-/**
- * @ngdoc filter
- * @name ng.filter:date
- * @function
- *
- * @description
- * Formats `date` to a string based on the requested `format`.
- *
- * `format` string can be composed of the following elements:
- *
- * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
- * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
- * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
- * * `'MMMM'`: Month in year (January-December)
- * * `'MMM'`: Month in year (Jan-Dec)
- * * `'MM'`: Month in year, padded (01-12)
- * * `'M'`: Month in year (1-12)
- * * `'dd'`: Day in month, padded (01-31)
- * * `'d'`: Day in month (1-31)
- * * `'EEEE'`: Day in Week,(Sunday-Saturday)
- * * `'EEE'`: Day in Week, (Sun-Sat)
- * * `'HH'`: Hour in day, padded (00-23)
- * * `'H'`: Hour in day (0-23)
- * * `'hh'`: Hour in am/pm, padded (01-12)
- * * `'h'`: Hour in am/pm, (1-12)
- * * `'mm'`: Minute in hour, padded (00-59)
- * * `'m'`: Minute in hour (0-59)
- * * `'ss'`: Second in minute, padded (00-59)
- * * `'s'`: Second in minute (0-59)
- * * `'a'`: am/pm marker
- * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200)
- *
- * `format` string can also be one of the following predefined
- * {@link guide/i18n localizable formats}:
- *
- * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
- * (e.g. Sep 3, 2010 12:05:08 pm)
- * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
- * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
- * (e.g. Friday, September 3, 2010)
- * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010
- * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
- * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
- * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
- * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
- *
- * `format` string can contain literal values. These need to be quoted with single quotes (e.g.
- * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
- * (e.g. `"h o''clock"`).
- *
- * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
- * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
- * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
- * specified in the string input, the time is considered to be in the local timezone.
- * @param {string=} format Formatting rules (see Description). If not specified,
- * `mediumDate` is used.
- * @returns {string} Formatted string or the input if input is not recognized as date/millis.
- *
- * @example
-
-
- {{1288323623006 | date:'medium'}} :
- {{1288323623006 | date:'medium'}}
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}} :
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
- {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}} :
- {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
-
-
- it('should format date', function() {
- expect(binding("1288323623006 | date:'medium'")).
- toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
- expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
- toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
- expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
- toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
- });
-
-
- */
-dateFilter.$inject = ['$locale'];
-function dateFilter($locale) {
-
-
- var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
- function jsonStringToDate(string){
- var match;
- if (match = string.match(R_ISO8601_STR)) {
- var date = new Date(0),
- tzHour = 0,
- tzMin = 0;
- if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
- }
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
- date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
- return date;
- }
- return string;
- }
-
-
- return function(date, format) {
- var text = '',
- parts = [],
- fn, match;
-
- format = format || 'mediumDate';
- format = $locale.DATETIME_FORMATS[format] || format;
- if (isString(date)) {
- if (NUMBER_STRING.test(date)) {
- date = int(date);
- } else {
- date = jsonStringToDate(date);
- }
- }
-
- if (isNumber(date)) {
- date = new Date(date);
- }
-
- if (!isDate(date)) {
- return date;
- }
-
- while(format) {
- match = DATE_FORMATS_SPLIT.exec(format);
- if (match) {
- parts = concat(parts, match, 1);
- format = parts.pop();
- } else {
- parts.push(format);
- format = null;
- }
- }
-
- forEach(parts, function(value){
- fn = DATE_FORMATS[value];
- text += fn ? fn(date, $locale.DATETIME_FORMATS)
- : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
- });
-
- return text;
- };
-}
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:json
- * @function
- *
- * @description
- * Allows you to convert a JavaScript object into JSON string.
- *
- * This filter is mostly useful for debugging. When using the double curly {{value}} notation
- * the binding is automatically converted to JSON.
- *
- * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
- * @returns {string} JSON string.
- *
- *
- * @example:
-
-
- {{ {'name':'value'} | json }}
-
-
- it('should jsonify filtered objects', function() {
- expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
- });
-
-
- *
- */
-function jsonFilter() {
- return function(object) {
- return toJson(object, true);
- };
-}
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:lowercase
- * @function
- * @description
- * Converts string to lowercase.
- * @see angular.lowercase
- */
-var lowercaseFilter = valueFn(lowercase);
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:uppercase
- * @function
- * @description
- * Converts string to uppercase.
- * @see angular.uppercase
- */
-var uppercaseFilter = valueFn(uppercase);
-
-/**
- * @ngdoc function
- * @name ng.filter:limitTo
- * @function
- *
- * @description
- * Creates a new array containing only a specified number of elements in an array. The elements
- * are taken from either the beginning or the end of the source array, as specified by the
- * value and sign (positive or negative) of `limit`.
- *
- * Note: This function is used to augment the `Array` type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
- * @param {Array} array Source array to be limited.
- * @param {string|Number} limit The length of the returned array. If the `limit` number is
- * positive, `limit` number of items from the beginning of the source array are copied.
- * If the number is negative, `limit` number of items from the end of the source array are
- * copied. The `limit` will be trimmed if it exceeds `array.length`
- * @returns {Array} A new sub-array of length `limit` or less if input array had less than `limit`
- * elements.
- *
- * @example
-
-
-
-
- Limit {{numbers}} to:
-
Output: {{ numbers | limitTo:limit }}
-
-
-
- it('should limit the numer array to first three items', function() {
- expect(element('.doc-example-live input[ng-model=limit]').val()).toBe('3');
- expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3]');
- });
-
- it('should update the output when -3 is entered', function() {
- input('limit').enter(-3);
- expect(binding('numbers | limitTo:limit')).toEqual('[7,8,9]');
- });
-
- it('should not exceed the maximum size of input array', function() {
- input('limit').enter(100);
- expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3,4,5,6,7,8,9]');
- });
-
-
- */
-function limitToFilter(){
- return function(array, limit) {
- if (!(array instanceof Array)) return array;
- limit = int(limit);
- var out = [],
- i, n;
-
- // check that array is iterable
- if (!array || !(array instanceof Array))
- return out;
-
- // if abs(limit) exceeds maximum length, trim it
- if (limit > array.length)
- limit = array.length;
- else if (limit < -array.length)
- limit = -array.length;
-
- if (limit > 0) {
- i = 0;
- n = limit;
- } else {
- i = array.length + limit;
- n = array.length;
- }
-
- for (; i} expression A predicate to be
- * used by the comparator to determine the order of elements.
- *
- * Can be one of:
- *
- * - `function`: Getter function. The result of this function will be sorted using the
- * `<`, `=`, `>` operator.
- * - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
- * to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
- * ascending or descending sort order (for example, +name or -name).
- * - `Array`: An array of function or string predicates. The first predicate in the array
- * is used for sorting, but when two items are equivalent, the next predicate is used.
- *
- * @param {boolean=} reverse Reverse the order the array.
- * @returns {Array} Sorted copy of the source array.
- *
- * @example
-
-
-
-
-
Sorting predicate = {{predicate}}; reverse = {{reverse}}
-
- [
unsorted ]
-
-
-
-
- it('should be reverse ordered by aged', function() {
- expect(binding('predicate')).toBe('-age');
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
- toEqual(['35', '29', '21', '19', '10']);
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
- });
-
- it('should reorder the table when user selects different predicate', function() {
- element('.doc-example-live a:contains("Name")').click();
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
- toEqual(['35', '10', '29', '19', '21']);
-
- element('.doc-example-live a:contains("Phone")').click();
- expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
- toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
- });
-
-
- */
-orderByFilter.$inject = ['$parse'];
-function orderByFilter($parse){
- return function(array, sortPredicate, reverseOrder) {
- if (!isArray(array)) return array;
- if (!sortPredicate) return array;
- sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
- sortPredicate = map(sortPredicate, function(predicate){
- var descending = false, get = predicate || identity;
- if (isString(predicate)) {
- if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
- descending = predicate.charAt(0) == '-';
- predicate = predicate.substring(1);
- }
- get = $parse(predicate);
- }
- return reverseComparator(function(a,b){
- return compare(get(a),get(b));
- }, descending);
- });
- var arrayCopy = [];
- for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
- return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
-
- function comparator(o1, o2){
- for ( var i = 0; i < sortPredicate.length; i++) {
- var comp = sortPredicate[i](o1, o2);
- if (comp !== 0) return comp;
- }
- return 0;
- }
- function reverseComparator(comp, descending) {
- return toBoolean(descending)
- ? function(a,b){return comp(b,a);}
- : comp;
- }
- function compare(v1, v2){
- var t1 = typeof v1;
- var t2 = typeof v2;
- if (t1 == t2) {
- if (t1 == "string") v1 = v1.toLowerCase();
- if (t1 == "string") v2 = v2.toLowerCase();
- if (v1 === v2) return 0;
- return v1 < v2 ? -1 : 1;
- } else {
- return t1 < t2 ? -1 : 1;
- }
- }
- }
-}
-
-function ngDirective(directive) {
- if (isFunction(directive)) {
- directive = {
- link: directive
- }
- }
- directive.restrict = directive.restrict || 'AC';
- return valueFn(directive);
-}
-
-/**
- * @ngdoc directive
- * @name ng.directive:a
- * @restrict E
- *
- * @description
- * Modifies the default behavior of html A tag, so that the default action is prevented when href
- * attribute is empty.
- *
- * The reasoning for this change is to allow easy creation of action links with `ngClick` directive
- * without changing the location or causing page reloads, e.g.:
- * `Save `
- */
-var htmlAnchorDirective = valueFn({
- restrict: 'E',
- compile: function(element, attr) {
-
- if (msie <= 8) {
-
- // turn link into a stylable link in IE
- // but only if it doesn't have name attribute, in which case it's an anchor
- if (!attr.href && !attr.name) {
- attr.$set('href', '');
- }
-
- // add a comment node to anchors to workaround IE bug that causes element content to be reset
- // to new attribute content if attribute is updated with value containing @ and element also
- // contains value with @
- // see issue #1949
- element.append(document.createComment('IE fix'));
- }
-
- return function(scope, element) {
- element.bind('click', function(event){
- // if we have no href url, then don't navigate anywhere.
- if (!element.attr('href')) {
- event.preventDefault();
- }
- });
- }
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngHref
- * @restrict A
- *
- * @description
- * Using Angular markup like {{hash}} in an href attribute makes
- * the page open to a wrong URL, if the user clicks that link before
- * angular has a chance to replace the {{hash}} with actual URL, the
- * link will be broken and will most likely return a 404 error.
- * The `ngHref` directive solves this problem.
- *
- * The buggy way to write it:
- *
- *
- *
- *
- * The correct way to write it:
- *
- *
- *
- *
- * @element A
- * @param {template} ngHref any string which can contain `{{}}` markup.
- *
- * @example
- * This example uses `link` variable inside `href` attribute:
-
-
-
- link 1 (link, don't reload)
- link 2 (link, don't reload)
- link 3 (link, reload!)
- anchor (link, don't reload)
- anchor (no link)
- link (link, change location)
-
-
- it('should execute ng-click but not reload when href without value', function() {
- element('#link-1').click();
- expect(input('value').val()).toEqual('1');
- expect(element('#link-1').attr('href')).toBe("");
- });
-
- it('should execute ng-click but not reload when href empty string', function() {
- element('#link-2').click();
- expect(input('value').val()).toEqual('2');
- expect(element('#link-2').attr('href')).toBe("");
- });
-
- it('should execute ng-click and change url when ng-href specified', function() {
- expect(element('#link-3').attr('href')).toBe("/123");
-
- element('#link-3').click();
- expect(browser().window().path()).toEqual('/123');
- });
-
- it('should execute ng-click but not reload when href empty string and name specified', function() {
- element('#link-4').click();
- expect(input('value').val()).toEqual('4');
- expect(element('#link-4').attr('href')).toBe('');
- });
-
- it('should execute ng-click but not reload when no href but name specified', function() {
- element('#link-5').click();
- expect(input('value').val()).toEqual('5');
- expect(element('#link-5').attr('href')).toBe(undefined);
- });
-
- it('should only change url when only ng-href', function() {
- input('value').enter('6');
- expect(element('#link-6').attr('href')).toBe('6');
-
- element('#link-6').click();
- expect(browser().location().url()).toEqual('/6');
- });
-
-
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSrc
- * @restrict A
- *
- * @description
- * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
- * work right: The browser will fetch from the URL with the literal
- * text `{{hash}}` until Angular replaces the expression inside
- * `{{hash}}`. The `ngSrc` directive solves this problem.
- *
- * The buggy way to write it:
- *
- *
- *
- *
- * The correct way to write it:
- *
- *
- *
- *
- * @element IMG
- * @param {template} ngSrc any string which can contain `{{}}` markup.
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngDisabled
- * @restrict A
- *
- * @description
- *
- * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
- *
- *
- * Disabled
- *
- *
- *
- * The HTML specs do not require browsers to preserve the special attributes such as disabled.
- * (The presence of them means true and absence means false)
- * This prevents the angular compiler from correctly retrieving the binding expression.
- * To solve this problem, we introduce the `ngDisabled` directive.
- *
- * @example
-
-
- Click me to toggle:
- Button
-
-
- it('should toggle button', function() {
- expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
- input('checked').check();
- expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
- });
-
-
- *
- * @element INPUT
- * @param {expression} ngDisabled Angular expression that will be evaluated.
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngChecked
- * @restrict A
- *
- * @description
- * The HTML specs do not require browsers to preserve the special attributes such as checked.
- * (The presence of them means true and absence means false)
- * This prevents the angular compiler from correctly retrieving the binding expression.
- * To solve this problem, we introduce the `ngChecked` directive.
- * @example
-
-
- Check me to check both:
-
-
-
- it('should check both checkBoxes', function() {
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
- input('master').check();
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
- });
-
-
- *
- * @element INPUT
- * @param {expression} ngChecked Angular expression that will be evaluated.
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMultiple
- * @restrict A
- *
- * @description
- * The HTML specs do not require browsers to preserve the special attributes such as multiple.
- * (The presence of them means true and absence means false)
- * This prevents the angular compiler from correctly retrieving the binding expression.
- * To solve this problem, we introduce the `ngMultiple` directive.
- *
- * @example
-
-
- Check me check multiple:
-
- Misko
- Igor
- Vojta
- Di
-
-
-
- it('should toggle multiple', function() {
- expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
- input('checked').check();
- expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
- });
-
-
- *
- * @element SELECT
- * @param {expression} ngMultiple Angular expression that will be evaluated.
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngReadonly
- * @restrict A
- *
- * @description
- * The HTML specs do not require browsers to preserve the special attributes such as readonly.
- * (The presence of them means true and absence means false)
- * This prevents the angular compiler from correctly retrieving the binding expression.
- * To solve this problem, we introduce the `ngReadonly` directive.
- * @example
-
-
- Check me to make text readonly:
-
-
-
- it('should toggle readonly attr', function() {
- expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
- input('checked').check();
- expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
- });
-
-
- *
- * @element INPUT
- * @param {string} expression Angular expression that will be evaluated.
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSelected
- * @restrict A
- *
- * @description
- * The HTML specs do not require browsers to preserve the special attributes such as selected.
- * (The presence of them means true and absence means false)
- * This prevents the angular compiler from correctly retrieving the binding expression.
- * To solve this problem, we introduced the `ngSelected` directive.
- * @example
-
-
- Check me to select:
-
- Hello!
- Greetings!
-
-
-
- it('should select Greetings!', function() {
- expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
- input('selected').check();
- expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
- });
-
-
- *
- * @element OPTION
- * @param {string} expression Angular expression that will be evaluated.
- */
-
-
-var ngAttributeAliasDirectives = {};
-
-
-// boolean attrs are evaluated
-forEach(BOOLEAN_ATTR, function(propName, attrName) {
- var normalized = directiveNormalize('ng-' + attrName);
- ngAttributeAliasDirectives[normalized] = function() {
- return {
- priority: 100,
- compile: function() {
- return function(scope, element, attr) {
- scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
- attr.$set(attrName, !!value);
- });
- };
- }
- };
- };
-});
-
-
-// ng-src, ng-href are interpolated
-forEach(['src', 'href'], function(attrName) {
- var normalized = directiveNormalize('ng-' + attrName);
- ngAttributeAliasDirectives[normalized] = function() {
- return {
- priority: 99, // it needs to run after the attributes are interpolated
- link: function(scope, element, attr) {
- attr.$observe(normalized, function(value) {
- if (!value)
- return;
-
- attr.$set(attrName, value);
-
- // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
- // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
- // to set the property as well to achieve the desired effect.
- // we use attr[attrName] value since $set can sanitize the url.
- if (msie) element.prop(attrName, attr[attrName]);
- });
- }
- };
- };
-});
-
-var nullFormCtrl = {
- $addControl: noop,
- $removeControl: noop,
- $setValidity: noop,
- $setDirty: noop
-};
-
-/**
- * @ngdoc object
- * @name ng.directive:form.FormController
- *
- * @property {boolean} $pristine True if user has not interacted with the form yet.
- * @property {boolean} $dirty True if user has already interacted with the form.
- * @property {boolean} $valid True if all of the containing forms and controls are valid.
- * @property {boolean} $invalid True if at least one containing control or form is invalid.
- *
- * @property {Object} $error Is an object hash, containing references to all invalid controls or
- * forms, where:
- *
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
- * - values are arrays of controls or forms that are invalid with given error.
- *
- * @description
- * `FormController` keeps track of all its controls and nested forms as well as state of them,
- * such as being valid/invalid or dirty/pristine.
- *
- * Each {@link ng.directive:form form} directive creates an instance
- * of `FormController`.
- *
- */
-//asks for $scope to fool the BC controller module
-FormController.$inject = ['$element', '$attrs', '$scope'];
-function FormController(element, attrs) {
- var form = this,
- parentForm = element.parent().controller('form') || nullFormCtrl,
- invalidCount = 0, // used to easily determine if we are valid
- errors = form.$error = {};
-
- // init state
- form.$name = attrs.name;
- form.$dirty = false;
- form.$pristine = true;
- form.$valid = true;
- form.$invalid = false;
-
- parentForm.$addControl(form);
-
- // Setup initial state of the control
- element.addClass(PRISTINE_CLASS);
- toggleValidCss(true);
-
- // convenience method for easy toggling of classes
- function toggleValidCss(isValid, validationErrorKey) {
- validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
- element.
- removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
- addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
- }
-
- form.$addControl = function(control) {
- if (control.$name && !form.hasOwnProperty(control.$name)) {
- form[control.$name] = control;
- }
- };
-
- form.$removeControl = function(control) {
- if (control.$name && form[control.$name] === control) {
- delete form[control.$name];
- }
- forEach(errors, function(queue, validationToken) {
- form.$setValidity(validationToken, true, control);
- });
- };
-
- form.$setValidity = function(validationToken, isValid, control) {
- var queue = errors[validationToken];
-
- if (isValid) {
- if (queue) {
- arrayRemove(queue, control);
- if (!queue.length) {
- invalidCount--;
- if (!invalidCount) {
- toggleValidCss(isValid);
- form.$valid = true;
- form.$invalid = false;
- }
- errors[validationToken] = false;
- toggleValidCss(true, validationToken);
- parentForm.$setValidity(validationToken, true, form);
- }
- }
-
- } else {
- if (!invalidCount) {
- toggleValidCss(isValid);
- }
- if (queue) {
- if (includes(queue, control)) return;
- } else {
- errors[validationToken] = queue = [];
- invalidCount++;
- toggleValidCss(false, validationToken);
- parentForm.$setValidity(validationToken, false, form);
- }
- queue.push(control);
-
- form.$valid = false;
- form.$invalid = true;
- }
- };
-
- form.$setDirty = function() {
- element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
- form.$dirty = true;
- form.$pristine = false;
- parentForm.$setDirty();
- };
-
-}
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngForm
- * @restrict EAC
- *
- * @description
- * Nestable alias of {@link ng.directive:form `form`} directive. HTML
- * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
- * sub-group of controls needs to be determined.
- *
- * @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
- * related scope, under this name.
- *
- */
-
- /**
- * @ngdoc directive
- * @name ng.directive:form
- * @restrict E
- *
- * @description
- * Directive that instantiates
- * {@link ng.directive:form.FormController FormController}.
- *
- * If `name` attribute is specified, the form controller is published onto the current scope under
- * this name.
- *
- * # Alias: {@link ng.directive:ngForm `ngForm`}
- *
- * In angular forms can be nested. This means that the outer form is valid when all of the child
- * forms are valid as well. However browsers do not allow nesting of `