Created
January 12, 2015 17:14
-
-
Save billjohnston/3d6bb61fdc7542c19b03 to your computer and use it in GitHub Desktop.
Old version of Resource Directives
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var resourceDirectives = angular.module('resourceDirectives', ['ui.bootstrap']); | |
var head = angular.element(document.querySelector('head')); | |
head.prepend('<style> .rd_loading .rd_text{visibility: hidden;} .rd_loading .rd_spinner{display: block;} .rd_loading .rd_spinner{display: block;} .rd_spinner{display: none;} .rd_spinner .fa{vertical-align: top;} .rd_position-relative{position: relative;} .rd_absolute-center{position: absolute; margin: auto; text-align: center; top:0; left:0; right:0; bottom:0; width: 1em; height: 1em;}</style>'); | |
resourceDirectives.factory('interpolate_url', [ | |
'resourceDirectivesConfig', '$location', | |
function(resourceDirectivesConfig, $location){ | |
return function(url, params, data){ | |
var match = url.match(/(\:[a-zA-Z_-]*)/g); | |
var strip_slashes; | |
var sub_with = params || data || {}; | |
_.each(match, function(url_sub){ | |
var regex = new RegExp(url_sub); | |
var param_key = url_sub.replace(':', ''); | |
if(param_key in sub_with){ | |
url = url.replace(regex, sub_with[param_key]); | |
delete sub_with[param_key]; | |
} | |
else{ | |
url = url.replace(regex, ''); | |
} | |
}); | |
url = url.replace(/(\/{2,})/, '/'); | |
try{ | |
strip_slashes = resourceDirectivesConfig.settings.strip_slashes; | |
} | |
catch(e){ | |
strip_slashes = true; | |
} | |
if(strip_slashes){ | |
url = url.replace(/\/+$/i, ""); | |
} | |
if(params && !_.isEmpty(params)){ | |
var parts = []; | |
for (var i in params) { | |
if (params.hasOwnProperty(i)) { | |
parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(params[i])); | |
} | |
} | |
url = url + '?' + parts.join("&"); | |
} | |
return url; | |
}; | |
}]); | |
resourceDirectives.factory('parse_pse', ['$rootScope', function($rootScope){ | |
return function(parse_this){ | |
if ($rootScope.$$phase) { | |
$rootScope.$evalAsync(parse_this); | |
} else { | |
$rootScope.$apply(parse_this); | |
} | |
}; | |
}]); | |
var trim_split = function(string_var){ | |
return string_var.replace(/^\s*|\s*$/g,'').split(/\s*,\s*/); | |
}; | |
var clean_boolean_string = function(str){ | |
return (str === 'true' || str === 'yes') || ((str === 'false' || str === 'no') ? false : str); | |
}; | |
resourceDirectives.factory( | |
'ajax', | |
[ | |
'$rootScope', | |
'$parse', | |
'resourceDirectivesConfig', | |
'$http', | |
'$modal', | |
'interpolate_url', | |
'parse_pse', | |
function($rootScope, $parse, resourceDirectivesConfig, $http, $modal, interpolate_url, parse_pse){ | |
var reset_loading = function(loading){ | |
if(_.isString(loading)){ | |
$rootScope[loading] = false; | |
} | |
else{ | |
loading.loading = false; | |
} | |
}; | |
var error_callbacks = function(form, loading){ | |
var modal_alert = function(data, status){ | |
var print_response = ''; | |
if(_.isObject(data)){ | |
_.each(data, function(val, key){ | |
print_response += '<li>' + key + ': ' + val + '</li>'; | |
}); | |
} | |
else if(_.isArray(data)){ | |
_.each(data, function(val, key){ | |
print_response += '<li>' + val + '</li>'; | |
}); | |
} | |
else if(_.isString(data)){ | |
print_response = data; | |
} | |
else{ | |
if(data){ | |
print_response = data; | |
} | |
else{ | |
print_response = 'Nothing returned'; | |
} | |
} | |
$rootScope.error_modal = $modal.open({ | |
windowClass: 'alert-modal', | |
template: | |
'<div class="alert alert-danger alert-dismissible margin-bottom-0" role="alert">' + | |
'<button class="close" ng-click="error_modal.dismiss(\'cancel\')">' + | |
'<span>×</span>' + | |
'</button>' + | |
'<h4 class="margin-bottom-0">' + | |
print_response + | |
'</h4>' + | |
'</div>' | |
}); | |
reset_loading(loading); | |
}; | |
if(form){ | |
if(status == 400){ | |
return function(data, status){ | |
form.$error = data; | |
reset_loading(loading); | |
}; | |
} | |
else{ | |
return modal_alert; | |
} | |
} | |
else{ | |
return modal_alert; | |
} | |
}; | |
return function(manager, model_name, method_obj, params, form, pse, alias, exclusive_field){ | |
var method, url, base_url, loading; | |
var alias_or_model_name = alias || model_name; | |
if(method_obj){ //false = manager | |
loading = method_obj; | |
method_obj.loading = true; | |
base_url = resourceDirectivesConfig.settings.base_url + | |
method_obj._resource.url; | |
var contains_this = []; | |
_.each(pse, function(value, key){ | |
if(value && value.indexOf('this') != -1){ | |
contains_this.push(key); | |
} | |
}); | |
if(contains_this.length){ | |
var resource_name = method_obj._resource.alias || method_obj._resource.name; | |
var method_obj_index = _.findIndex( | |
$rootScope[resource_name], | |
{$$hashKey: method_obj.$$hashKey} | |
); | |
_.each(contains_this, function(key){ | |
pse[key] = pse[key].replace( | |
'this', | |
resource_name + '[' + method_obj_index + ']' | |
); | |
}); | |
} | |
} | |
else{ | |
loading = alias_or_model_name + '_loading'; | |
$rootScope[loading] = true; | |
var model_config = resourceDirectivesConfig.models[model_name]; | |
model_config.name = model_name; | |
model_config.alias = alias; | |
base_url = resourceDirectivesConfig.settings.base_url + | |
resourceDirectivesConfig.models[model_name].url; | |
} | |
if(pse.pre){ | |
parse_pse(pse.pre); | |
} | |
switch(manager){ | |
case 'rdToggle': | |
case 'rdUpdate': | |
method = resourceDirectivesConfig.settings.update_method.toLowerCase() || 'post'; | |
args = [interpolate_url(base_url, null, params), params]; | |
break; | |
case 'rdCreate': | |
method = 'post'; | |
args = [interpolate_url(base_url, null, params), params]; | |
break; | |
case 'rdQuery': | |
case 'rdQueryOnce': | |
$rootScope[model_name] = undefined; | |
method = 'get'; | |
args = [interpolate_url(base_url, params)]; | |
break; | |
case 'rdGetSingle': | |
case 'rdGet': | |
method = 'get'; | |
args = [interpolate_url(base_url, params)]; | |
break; | |
} | |
var ajax_call = $http[method].apply(this, args) | |
.success(function(response){ | |
var objects = angular.isArray(response) ? response : [response]; | |
if(!method_obj){ | |
objects = _.map(objects, function(map_response){ | |
return _.merge( | |
map_response, | |
{_resource: model_config, _errors: {}} | |
); | |
}); | |
} | |
switch(manager){ | |
case 'rdGet': | |
if (alias_or_model_name in $rootScope){ | |
_.forEach(response, function(each_resp){ | |
var found_index = _.findIndex( | |
$rootScope[alias_or_model_name], | |
{id: each_resp.id} | |
); | |
if(found_index != -1){ | |
$rootScope[alias_or_model_name][found_index] = each_resp; | |
} | |
else{ | |
$rootScope[alias_or_model_name].push(each_resp); | |
} | |
}); | |
} | |
else{ | |
$rootScope[alias_or_model_name] = response; | |
} | |
break; | |
case 'rdGetSingle': | |
if(_.isArray(response)){ | |
$rootScope[alias_or_model_name] = response[0]; | |
} | |
else{ | |
$rootScope[alias_or_model_name] = response; | |
} | |
break; | |
case 'rdCreate': | |
if (alias_or_model_name in $rootScope){ | |
$rootScope[alias_or_model_name].push(response); | |
} | |
else{ | |
$rootScope[alias_or_model_name] = [response]; | |
} | |
break; | |
case 'rdQuery': | |
case 'rdQueryOnce': | |
$rootScope[alias_or_model_name] = objects; | |
break; | |
case 'rdUpdate': | |
if(!method_obj){ | |
var found_index = _.findIndex( | |
$rootScope[alias_or_model_name], | |
{id: response.id} | |
); | |
if(found_index != -1){ | |
$rootScope[alias_or_model_name][found_index] = response; | |
} | |
else{ | |
$rootScope[alias_or_model_name].push(response); | |
} | |
} | |
else{ | |
if(exclusive_field){ | |
$rootScope[alias_or_model_name] = _.map( | |
$rootScope[alias_or_model_name], function(obj){ | |
obj[exclusive_field] = !response[exclusive_field]; | |
return obj; | |
} | |
); | |
} | |
method_obj = _.assign(method_obj, response); | |
} | |
break; | |
} | |
reset_loading(loading); | |
}) | |
.error(error_callbacks(form, loading)) | |
.then(function(response){ | |
_.defer(function(){ | |
if(response.status == 200 && pse.success){ | |
parse_pse(pse.success); | |
} | |
else if(pse.error){ | |
parse_pse(pse.error); | |
} | |
}); | |
}); | |
}; | |
}]); | |
// Button loading directive | |
resourceDirectives.directive('loading', function() { | |
return { | |
restrict: 'A', | |
transclude: true, | |
scope: { | |
loading: '=' | |
}, | |
template: | |
"<div class='rd_position-relative' ng-class='{rd_loading: loading}'>" + | |
"<span class='rd_absolute-center rd_spinner'>" + | |
"<span class='fa fa-spin fa-circle-o-notch'></span>" + | |
"</span>" + | |
"<span class='rd_text' ng-transclude></span>" + | |
"</div>" | |
}; | |
}); | |
// Create directive for each model manager/method | |
var model_managers = ['rdGet', 'rdGetSingle', 'rdQuery', 'rdQueryOnce', 'rdCreate']; | |
var model_methods = ['rdUpdate', 'rdToggle']; | |
var combined = _.union(model_managers, model_methods); | |
_.each(combined, function(directive_attr){ | |
resourceDirectives.directive(directive_attr, ['$rootScope', 'ajax', '$parse', function($rootScope, ajax, $parse) { | |
return { | |
restrict: 'A', | |
require: '^?form', | |
link: function(scope, element, attrs, form){ | |
var method = (model_methods.indexOf(directive_attr) != -1 && !('rdManager' in attrs)); | |
var bind_event; | |
var params = {}; | |
switch(element.prop('tagName')){ | |
case 'FORM': | |
bind_event = 'submit'; | |
break; | |
case 'BUTTON': | |
case 'A': | |
bind_event = 'click'; | |
break; | |
case 'LI': | |
// If its a tab (ui-bootstrap) | |
if(element.parent().hasClass("nav-[[type || 'tabs']]")){ | |
// This parts a little janky | |
bind_event = 'select'; | |
var elem = element[0]; | |
var elindex = Array.prototype.indexOf.call( | |
elem.parentNode.childNodes, | |
elem | |
); | |
var modified_index = (elindex - 1) / 2; | |
scope.$parent.tabs[modified_index].$watch('active', function(active){ | |
if(active){ | |
element.triggerHandler('select'); | |
} | |
}); | |
} | |
break; | |
} | |
var run_resource_fn = function(event){ | |
var method_obj = method ? scope[attrs[directive_attr]] : false; | |
var model_name = method ? method_obj._resource.name : attrs[directive_attr]; | |
var params; | |
if(directive_attr == 'rdQueryOnce'){ | |
element.off(bind_event); | |
} | |
if(element.prop('tagName') == 'FORM'){ | |
params = {}; | |
_.each(['input', 'select', 'textarea'], function(tag){ | |
_.each(element.find(tag), function(field){ | |
var ng_field = angular.element(field); | |
var field_name = ng_field.attr('name'); | |
if(!_.isEmpty(field_name)){ | |
if(ng_field.attr('type') == 'radio'){ | |
if(ng_field.prop('checked')){ | |
params[field_name] = clean_boolean_string(ng_field.val()); | |
} | |
} | |
else{ | |
params[field_name] = clean_boolean_string(ng_field.val()); | |
} | |
} | |
}); | |
}); | |
} | |
//if any attribute contains rd-val- | |
else if(_.any(attrs, function(value, attr){return attr.indexOf('rdVal') != -1;})){ | |
params = {}; | |
_.each(attrs, function(value, attr){ | |
if(attr.indexOf('rdVal') != -1){ | |
// camelcase to underscores | |
var param_key = attr.replace( | |
/([A-Z])/g, | |
function($1){ | |
return "_" + $1.toLowerCase(); | |
} | |
).replace('rd_val_', ''); | |
attrs[attr] = clean_boolean_string(attrs[attr]); | |
params[param_key] = attrs[attr]; | |
} | |
}); | |
} | |
else if(attrs.rdFields && method){ | |
var params_from_obj = method_obj; | |
var fields_array = trim_split(attrs.rdFields); | |
if(directive_attr == 'rdToggle'){ | |
_.each(fields_array, function(field){ | |
params_from_obj[field] = !params_from_obj[field]; | |
}); | |
} | |
params = _.pick(params_from_obj, fields_array); | |
} | |
else if(method){ | |
params = _.omit(method_obj, ['_resource', '_errors']); | |
} | |
var alias = attrs.rdAlias; | |
_.each(['rdPre', 'rdSuccess', 'rdError'], function(pse){ | |
if(attrs[pse]){ | |
var fn = $parse(attrs[pse], null, true); | |
attrs[pse] = function() { | |
fn(scope, {$event: event}); | |
}; | |
} | |
}); | |
ajax( | |
directive_attr, | |
model_name, | |
method_obj, | |
params, | |
form, | |
{ | |
pre: attrs.rdPre, | |
success: attrs.rdSuccess, | |
error: attrs.rdError | |
}, | |
alias, | |
attrs.rdExclusiveField | |
); | |
}; | |
if(bind_event){ | |
element.on(bind_event, run_resource_fn); | |
} | |
else{ | |
run_resource_fn(); | |
} | |
} | |
}; | |
}]); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment