decidim-core 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/assets/config/decidim_core_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim.js.es6 +3 -2
  5. data/app/assets/javascripts/decidim/append_elements.js.es6 +8 -0
  6. data/app/assets/javascripts/decidim/filters.js.es6 +22 -0
  7. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +176 -0
  8. data/app/assets/javascripts/decidim/form_filter.component.test.js +151 -0
  9. data/app/assets/javascripts/decidim/inline_svg.js.es6 +12 -0
  10. data/app/assets/javascripts/decidim/user_registrations.js.es6 +22 -0
  11. data/app/assets/stylesheets/decidim/_variables.scss +1 -1
  12. data/app/assets/stylesheets/decidim/modules/_comments.scss +3 -6
  13. data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +22 -0
  14. data/app/assets/stylesheets/decidim/modules/_layout.scss +9 -1
  15. data/app/assets/stylesheets/decidim/modules/_navbar.scss +8 -5
  16. data/app/assets/stylesheets/decidim/modules/_order-by.scss +0 -1
  17. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +4 -0
  18. data/app/assets/stylesheets/decidim/modules/_timeline.scss +62 -80
  19. data/app/assets/stylesheets/decidim/modules/_typography.scss +20 -31
  20. data/app/assets/stylesheets/decidim/utils/_fontface.scss +4 -16
  21. data/app/assets/stylesheets/decidim/utils/_settings.scss +29 -26
  22. data/app/assets/stylesheets/decidim/utils/_variables.scss +22 -0
  23. data/app/commands/decidim/authorize_user.rb +17 -1
  24. data/app/commands/decidim/create_omniauth_registration.rb +92 -0
  25. data/app/commands/decidim/create_registration.rb +50 -0
  26. data/app/commands/decidim/invite_user.rb +50 -0
  27. data/app/commands/decidim/invite_user_again.rb +25 -0
  28. data/app/commands/decidim/remove_user_role.rb +26 -0
  29. data/app/controllers/concerns/decidim/feature_settings.rb +27 -0
  30. data/app/controllers/concerns/decidim/filter_resource.rb +71 -0
  31. data/app/controllers/concerns/decidim/form_factory.rb +21 -18
  32. data/app/controllers/concerns/decidim/needs_participatory_process.rb +2 -3
  33. data/app/controllers/decidim/devise/confirmations_controller.rb +2 -0
  34. data/app/controllers/decidim/devise/invitations_controller.rb +4 -0
  35. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +96 -0
  36. data/app/controllers/decidim/devise/passwords_controller.rb +2 -0
  37. data/app/controllers/decidim/devise/registrations_controller.rb +34 -0
  38. data/app/controllers/decidim/devise/sessions_controller.rb +1 -0
  39. data/app/controllers/decidim/pages_controller.rb +10 -2
  40. data/app/controllers/decidim/participatory_process_steps_controller.rb +16 -0
  41. data/app/controllers/decidim/participatory_processes_controller.rb +6 -11
  42. data/app/forms/decidim/form.rb +6 -6
  43. data/app/forms/decidim/invite_admin_form.rb +37 -0
  44. data/app/forms/decidim/omniauth_registration_form.rb +24 -0
  45. data/app/forms/decidim/registration_form.rb +41 -0
  46. data/app/helpers/decidim/filters_helper.rb +21 -0
  47. data/app/helpers/decidim/layout_helper.rb +17 -1
  48. data/app/helpers/decidim/omniauth_helper.rb +23 -0
  49. data/app/helpers/decidim/paginate_helper.rb +21 -0
  50. data/app/helpers/decidim/participatory_process_helper.rb +14 -0
  51. data/app/helpers/decidim/participatory_process_steps_helper.rb +17 -0
  52. data/app/mailers/decidim/decidim_devise_mailer.rb +2 -2
  53. data/app/models/decidim/feature.rb +40 -0
  54. data/app/models/decidim/identity.rb +12 -0
  55. data/app/models/decidim/organization.rb +3 -10
  56. data/app/models/decidim/user.rb +3 -1
  57. data/app/models/decidim/user_group.rb +18 -0
  58. data/app/models/decidim/user_group_membership.rb +9 -0
  59. data/app/services/decidim/authorization_handler.rb +13 -13
  60. data/app/services/decidim/resource_search.rb +52 -0
  61. data/app/uploaders/decidim/organization_logo_uploader.rb +1 -1
  62. data/app/views/decidim/authorizations/new.html.erb +3 -1
  63. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +40 -0
  64. data/app/views/decidim/devise/registrations/new.html.erb +21 -1
  65. data/app/views/decidim/devise/sessions/new.html.erb +1 -0
  66. data/app/views/decidim/devise/shared/_links.html.erb +0 -8
  67. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +21 -0
  68. data/app/views/decidim/participatory_process_steps/_participatory_process_step.html.erb +16 -0
  69. data/app/views/decidim/participatory_process_steps/_timeline.html.erb +7 -0
  70. data/app/views/decidim/participatory_process_steps/index.html.erb +12 -0
  71. data/app/views/decidim/participatory_processes/show.html.erb +5 -5
  72. data/app/views/decidim/shared/_login_modal.html.erb +30 -0
  73. data/app/views/devise/mailer/invite_admin.html.erb +17 -0
  74. data/app/views/devise/mailer/invite_admin.text.erb +15 -0
  75. data/app/views/devise/mailer/organization_admin_invitation_instructions.html.erb +1 -1
  76. data/app/views/devise/mailer/organization_admin_invitation_instructions.text.erb +1 -1
  77. data/app/views/layouts/decidim/_application.html.erb +1 -0
  78. data/app/views/layouts/decidim/_header.html.erb +1 -1
  79. data/app/views/layouts/decidim/_meta.html.erb +1 -0
  80. data/app/views/layouts/decidim/_process_header.html.erb +12 -1
  81. data/app/views/layouts/decidim/_process_header_steps.html.erb +1 -0
  82. data/app/views/layouts/decidim/_social_meta.html.erb +11 -0
  83. data/app/views/layouts/decidim/participatory_process.html.erb +4 -0
  84. data/app/views/pages/home.html.erb +29 -2
  85. data/config/i18n-tasks.yml +1 -0
  86. data/config/initializers/devise.rb +10 -1
  87. data/config/locales/ca.yml +45 -3
  88. data/config/locales/en.yml +45 -3
  89. data/config/locales/es.yml +45 -3
  90. data/config/routes.rb +9 -2
  91. data/config/secrets.yml +36 -0
  92. data/db/migrate/20170110133113_add_configuration_to_features.rb +7 -0
  93. data/db/migrate/20170110153807_add_handler_to_organization.rb +5 -0
  94. data/db/migrate/20170116110851_create_identities.rb +11 -0
  95. data/db/migrate/20170116135237_loosen_step_requirements.rb +6 -0
  96. data/db/migrate/20170117142904_add_uniqueness_field_to_authorizations.rb +7 -0
  97. data/db/migrate/20170119145359_create_user_groups.rb +11 -0
  98. data/db/migrate/20170119150255_create_user_group_memberships.rb +12 -0
  99. data/db/migrate/20170119150649_add_show_statistics_to_organization.rb +5 -0
  100. data/db/migrate/20170120120733_add_user_groups_verified.rb +5 -0
  101. data/db/seeds.rb +45 -79
  102. data/lib/decidim/core.rb +8 -0
  103. data/lib/decidim/core/engine.rb +8 -0
  104. data/lib/decidim/core/test/factories.rb +188 -0
  105. data/lib/decidim/core/version.rb +1 -1
  106. data/lib/decidim/devise_failure_app.rb +1 -0
  107. data/lib/decidim/feature_manifest.rb +27 -0
  108. data/lib/decidim/features/base_controller.rb +8 -3
  109. data/lib/decidim/features/settings_manifest.rb +94 -0
  110. data/lib/decidim/filter_form_builder.rb +56 -0
  111. data/lib/decidim/form_builder.rb +4 -7
  112. data/vendor/assets/javascripts/svg-injector.js +464 -0
  113. metadata +142 -26
  114. data/app/assets/stylesheets/decidim/modules/_owl-carousel.scss +0 -72
  115. data/app/assets/stylesheets/decidim/modules/_phase-nav.scss +0 -177
  116. data/app/assets/stylesheets/decidim/utils/_helpers.sass +0 -21
  117. data/app/assets/stylesheets/decidim/utils/_keyframes.sass +0 -13
  118. data/app/assets/stylesheets/decidim/utils/_mixins.sass +0 -33
@@ -32,7 +32,7 @@ module Decidim
32
32
  string + content_tag(:li, class: tab_element_class_for("title", index)) do
33
33
  title = I18n.t(locale, scope: "locales")
34
34
  element_class = ""
35
- element_class += "alert" if has_error?(name_with_locale(name, locale))
35
+ element_class += "alert" if error?(name_with_locale(name, locale))
36
36
  content_tag(:a, title, href: "##{name}-panel-#{index}", class: element_class)
37
37
  end
38
38
  end
@@ -71,7 +71,7 @@ module Decidim
71
71
  template += content_tag(:div, nil, class: "editor-container", data: {
72
72
  toolbar: options[:toolbar]
73
73
  }, style: "height: #{options[:lines]}rem")
74
- template += error_for(name, options) if has_error?(name)
74
+ template += error_for(name, options) if error?(name)
75
75
  template.html_safe
76
76
  end
77
77
  end
@@ -87,23 +87,20 @@ module Decidim
87
87
  # Returns a String.
88
88
  def categories_select(name, collection, options = {})
89
89
  options = {
90
- prompt: nil,
91
90
  disable_parents: true
92
91
  }.merge(options)
93
92
 
94
- prompt = options[:prompt]
95
93
  disable_parents = options[:disable_parents]
96
94
 
97
95
  selected = object.send(name)
98
96
  categories = categories_for_select(collection)
99
- categories = [[prompt]] + categories if prompt
100
97
  disabled = if disable_parents
101
98
  disabled_categories_for(collection)
102
99
  else
103
100
  []
104
101
  end
105
102
 
106
- select(name, @template.options_for_select(categories, selected: selected, disabled: disabled))
103
+ select(name, @template.options_for_select(categories, selected: selected, disabled: disabled), options)
107
104
  end
108
105
 
109
106
  private
@@ -159,7 +156,7 @@ module Decidim
159
156
  end
160
157
 
161
158
  def label_i18n(attribute, text = nil, options = {})
162
- errored = has_error?(attribute) || locales.any? { |locale| has_error?(name_with_locale(attribute, locale)) }
159
+ errored = error?(attribute) || locales.any? { |locale| error?(name_with_locale(attribute, locale)) }
163
160
 
164
161
  if errored
165
162
  options[:class] ||= ""
@@ -0,0 +1,464 @@
1
+ /**
2
+ * SVGInjector v1.1.3 - Fast, caching, dynamic inline SVG DOM injection library
3
+ * https://github.com/iconic/SVGInjector
4
+ *
5
+ * Copyright (c) 2014-2015 Waybury <hello@waybury.com>
6
+ * @license MIT
7
+ */
8
+
9
+ (function (window, document) {
10
+
11
+ 'use strict';
12
+
13
+ // Environment
14
+ var isLocal = window.location.protocol === 'file:';
15
+ var hasSvgSupport = document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');
16
+
17
+ function uniqueClasses(list) {
18
+ list = list.split(' ');
19
+
20
+ var hash = {};
21
+ var i = list.length;
22
+ var out = [];
23
+
24
+ while (i--) {
25
+ if (!hash.hasOwnProperty(list[i])) {
26
+ hash[list[i]] = 1;
27
+ out.unshift(list[i]);
28
+ }
29
+ }
30
+
31
+ return out.join(' ');
32
+ }
33
+
34
+ /**
35
+ * cache (or polyfill for <= IE8) Array.forEach()
36
+ * source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
37
+ */
38
+ var forEach = Array.prototype.forEach || function (fn, scope) {
39
+ if (this === void 0 || this === null || typeof fn !== 'function') {
40
+ throw new TypeError();
41
+ }
42
+
43
+ /* jshint bitwise: false */
44
+ var i, len = this.length >>> 0;
45
+ /* jshint bitwise: true */
46
+
47
+ for (i = 0; i < len; ++i) {
48
+ if (i in this) {
49
+ fn.call(scope, this[i], i, this);
50
+ }
51
+ }
52
+ };
53
+
54
+ // SVG Cache
55
+ var svgCache = {};
56
+
57
+ var injectCount = 0;
58
+ var injectedElements = [];
59
+
60
+ // Request Queue
61
+ var requestQueue = [];
62
+
63
+ // Script running status
64
+ var ranScripts = {};
65
+
66
+ var cloneSvg = function (sourceSvg) {
67
+ return sourceSvg.cloneNode(true);
68
+ };
69
+
70
+ var queueRequest = function (url, callback) {
71
+ requestQueue[url] = requestQueue[url] || [];
72
+ requestQueue[url].push(callback);
73
+ };
74
+
75
+ var processRequestQueue = function (url) {
76
+ for (var i = 0, len = requestQueue[url].length; i < len; i++) {
77
+ // Make these calls async so we avoid blocking the page/renderer
78
+ /* jshint loopfunc: true */
79
+ (function (index) {
80
+ setTimeout(function () {
81
+ requestQueue[url][index](cloneSvg(svgCache[url]));
82
+ }, 0);
83
+ })(i);
84
+ /* jshint loopfunc: false */
85
+ }
86
+ };
87
+
88
+ var loadSvg = function (url, callback) {
89
+ if (svgCache[url] !== undefined) {
90
+ if (svgCache[url] instanceof SVGSVGElement) {
91
+ // We already have it in cache, so use it
92
+ callback(cloneSvg(svgCache[url]));
93
+ }
94
+ else {
95
+ // We don't have it in cache yet, but we are loading it, so queue this request
96
+ queueRequest(url, callback);
97
+ }
98
+ }
99
+ else {
100
+
101
+ if (!window.XMLHttpRequest) {
102
+ callback('Browser does not support XMLHttpRequest');
103
+ return false;
104
+ }
105
+
106
+ // Seed the cache to indicate we are loading this URL already
107
+ svgCache[url] = {};
108
+ queueRequest(url, callback);
109
+
110
+ var httpRequest = new XMLHttpRequest();
111
+
112
+ httpRequest.onreadystatechange = function () {
113
+ // readyState 4 = complete
114
+ if (httpRequest.readyState === 4) {
115
+
116
+ // Handle status
117
+ if (httpRequest.status === 404 || httpRequest.responseXML === null) {
118
+ callback('Unable to load SVG file: ' + url);
119
+
120
+ if (isLocal) callback('Note: SVG injection ajax calls do not work locally without adjusting security setting in your browser. Or consider using a local webserver.');
121
+
122
+ callback();
123
+ return false;
124
+ }
125
+
126
+ // 200 success from server, or 0 when using file:// protocol locally
127
+ if (httpRequest.status === 200 || (isLocal && httpRequest.status === 0)) {
128
+
129
+ /* globals Document */
130
+ if (httpRequest.responseXML instanceof Document) {
131
+ // Cache it
132
+ svgCache[url] = httpRequest.responseXML.documentElement;
133
+ }
134
+ /* globals -Document */
135
+
136
+ // IE9 doesn't create a responseXML Document object from loaded SVG,
137
+ // and throws a "DOM Exception: HIERARCHY_REQUEST_ERR (3)" error when injected.
138
+ //
139
+ // So, we'll just create our own manually via the DOMParser using
140
+ // the the raw XML responseText.
141
+ //
142
+ // :NOTE: IE8 and older doesn't have DOMParser, but they can't do SVG either, so...
143
+ else if (DOMParser && (DOMParser instanceof Function)) {
144
+ var xmlDoc;
145
+ try {
146
+ var parser = new DOMParser();
147
+ xmlDoc = parser.parseFromString(httpRequest.responseText, 'text/xml');
148
+ }
149
+ catch (e) {
150
+ xmlDoc = undefined;
151
+ }
152
+
153
+ if (!xmlDoc || xmlDoc.getElementsByTagName('parsererror').length) {
154
+ callback('Unable to parse SVG file: ' + url);
155
+ return false;
156
+ }
157
+ else {
158
+ // Cache it
159
+ svgCache[url] = xmlDoc.documentElement;
160
+ }
161
+ }
162
+
163
+ // We've loaded a new asset, so process any requests waiting for it
164
+ processRequestQueue(url);
165
+ }
166
+ else {
167
+ callback('There was a problem injecting the SVG: ' + httpRequest.status + ' ' + httpRequest.statusText);
168
+ return false;
169
+ }
170
+ }
171
+ };
172
+
173
+ httpRequest.open('GET', url);
174
+
175
+ // Treat and parse the response as XML, even if the
176
+ // server sends us a different mimetype
177
+ if (httpRequest.overrideMimeType) httpRequest.overrideMimeType('text/xml');
178
+
179
+ httpRequest.send();
180
+ }
181
+ };
182
+
183
+ // Inject a single element
184
+ var injectElement = function (el, evalScripts, pngFallback, callback) {
185
+
186
+ // Grab the src or data-src attribute
187
+ var imgUrl = el.getAttribute('data-src') || el.getAttribute('src');
188
+
189
+ // We can only inject SVG
190
+ if (!(/\.svg/i).test(imgUrl)) {
191
+ callback('Attempted to inject a file with a non-svg extension: ' + imgUrl);
192
+ return;
193
+ }
194
+
195
+ // If we don't have SVG support try to fall back to a png,
196
+ // either defined per-element via data-fallback or data-png,
197
+ // or globally via the pngFallback directory setting
198
+ if (!hasSvgSupport) {
199
+ var perElementFallback = el.getAttribute('data-fallback') || el.getAttribute('data-png');
200
+
201
+ // Per-element specific PNG fallback defined, so use that
202
+ if (perElementFallback) {
203
+ el.setAttribute('src', perElementFallback);
204
+ callback(null);
205
+ }
206
+ // Global PNG fallback directoriy defined, use the same-named PNG
207
+ else if (pngFallback) {
208
+ el.setAttribute('src', pngFallback + '/' + imgUrl.split('/').pop().replace('.svg', '.png'));
209
+ callback(null);
210
+ }
211
+ // um...
212
+ else {
213
+ callback('This browser does not support SVG and no PNG fallback was defined.');
214
+ }
215
+
216
+ return;
217
+ }
218
+
219
+ // Make sure we aren't already in the process of injecting this element to
220
+ // avoid a race condition if multiple injections for the same element are run.
221
+ // :NOTE: Using indexOf() only _after_ we check for SVG support and bail,
222
+ // so no need for IE8 indexOf() polyfill
223
+ if (injectedElements.indexOf(el) !== -1) {
224
+ return;
225
+ }
226
+
227
+ // Remember the request to inject this element, in case other injection
228
+ // calls are also trying to replace this element before we finish
229
+ injectedElements.push(el);
230
+
231
+ // Try to avoid loading the orginal image src if possible.
232
+ el.setAttribute('src', '');
233
+
234
+ // Load it up
235
+ loadSvg(imgUrl, function (svg) {
236
+
237
+ if (typeof svg === 'undefined' || typeof svg === 'string') {
238
+ callback(svg);
239
+ return false;
240
+ }
241
+
242
+ var imgId = el.getAttribute('id');
243
+ if (imgId) {
244
+ svg.setAttribute('id', imgId);
245
+ }
246
+
247
+ var imgTitle = el.getAttribute('title');
248
+ if (imgTitle) {
249
+ svg.setAttribute('title', imgTitle);
250
+ }
251
+
252
+ // Concat the SVG classes + 'injected-svg' + the img classes
253
+ var classMerge = [].concat(svg.getAttribute('class') || [], 'injected-svg', el.getAttribute('class') || []).join(' ');
254
+ svg.setAttribute('class', uniqueClasses(classMerge));
255
+
256
+ var imgStyle = el.getAttribute('style');
257
+ if (imgStyle) {
258
+ svg.setAttribute('style', imgStyle);
259
+ }
260
+
261
+ // Copy all the data elements to the svg
262
+ var imgData = [].filter.call(el.attributes, function (at) {
263
+ return (/^data-\w[\w\-]*$/).test(at.name);
264
+ });
265
+ forEach.call(imgData, function (dataAttr) {
266
+ if (dataAttr.name && dataAttr.value) {
267
+ svg.setAttribute(dataAttr.name, dataAttr.value);
268
+ }
269
+ });
270
+
271
+ // Make sure any internally referenced clipPath ids and their
272
+ // clip-path references are unique.
273
+ //
274
+ // This addresses the issue of having multiple instances of the
275
+ // same SVG on a page and only the first clipPath id is referenced.
276
+ //
277
+ // Browsers often shortcut the SVG Spec and don't use clipPaths
278
+ // contained in parent elements that are hidden, so if you hide the first
279
+ // SVG instance on the page, then all other instances lose their clipping.
280
+ // Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=376027
281
+
282
+ // Handle all defs elements that have iri capable attributes as defined by w3c: http://www.w3.org/TR/SVG/linking.html#processingIRI
283
+ // Mapping IRI addressable elements to the properties that can reference them:
284
+ var iriElementsAndProperties = {
285
+ 'clipPath': ['clip-path'],
286
+ 'color-profile': ['color-profile'],
287
+ 'cursor': ['cursor'],
288
+ 'filter': ['filter'],
289
+ 'linearGradient': ['fill', 'stroke'],
290
+ 'marker': ['marker', 'marker-start', 'marker-mid', 'marker-end'],
291
+ 'mask': ['mask'],
292
+ 'pattern': ['fill', 'stroke'],
293
+ 'radialGradient': ['fill', 'stroke']
294
+ };
295
+
296
+ var element, elementDefs, properties, currentId, newId;
297
+ Object.keys(iriElementsAndProperties).forEach(function (key) {
298
+ element = key;
299
+ properties = iriElementsAndProperties[key];
300
+
301
+ elementDefs = svg.querySelectorAll('defs ' + element + '[id]');
302
+ for (var i = 0, elementsLen = elementDefs.length; i < elementsLen; i++) {
303
+ currentId = elementDefs[i].id;
304
+ newId = currentId + '-' + injectCount;
305
+
306
+ // All of the properties that can reference this element type
307
+ var referencingElements;
308
+ forEach.call(properties, function (property) {
309
+ // :NOTE: using a substring match attr selector here to deal with IE "adding extra quotes in url() attrs"
310
+ referencingElements = svg.querySelectorAll('[' + property + '*="' + currentId + '"]');
311
+ for (var j = 0, referencingElementLen = referencingElements.length; j < referencingElementLen; j++) {
312
+ referencingElements[j].setAttribute(property, 'url(#' + newId + ')');
313
+ }
314
+ });
315
+
316
+ elementDefs[i].id = newId;
317
+ }
318
+ });
319
+
320
+ // Remove any unwanted/invalid namespaces that might have been added by SVG editing tools
321
+ svg.removeAttribute('xmlns:a');
322
+
323
+ // Post page load injected SVGs don't automatically have their script
324
+ // elements run, so we'll need to make that happen, if requested
325
+
326
+ // Find then prune the scripts
327
+ var scripts = svg.querySelectorAll('script');
328
+ var scriptsToEval = [];
329
+ var script, scriptType;
330
+
331
+ for (var k = 0, scriptsLen = scripts.length; k < scriptsLen; k++) {
332
+ scriptType = scripts[k].getAttribute('type');
333
+
334
+ // Only process javascript types.
335
+ // SVG defaults to 'application/ecmascript' for unset types
336
+ if (!scriptType || scriptType === 'application/ecmascript' || scriptType === 'application/javascript') {
337
+
338
+ // innerText for IE, textContent for other browsers
339
+ script = scripts[k].innerText || scripts[k].textContent;
340
+
341
+ // Stash
342
+ scriptsToEval.push(script);
343
+
344
+ // Tidy up and remove the script element since we don't need it anymore
345
+ svg.removeChild(scripts[k]);
346
+ }
347
+ }
348
+
349
+ // Run/Eval the scripts if needed
350
+ if (scriptsToEval.length > 0 && (evalScripts === 'always' || (evalScripts === 'once' && !ranScripts[imgUrl]))) {
351
+ for (var l = 0, scriptsToEvalLen = scriptsToEval.length; l < scriptsToEvalLen; l++) {
352
+
353
+ // :NOTE: Yup, this is a form of eval, but it is being used to eval code
354
+ // the caller has explictely asked to be loaded, and the code is in a caller
355
+ // defined SVG file... not raw user input.
356
+ //
357
+ // Also, the code is evaluated in a closure and not in the global scope.
358
+ // If you need to put something in global scope, use 'window'
359
+ new Function(scriptsToEval[l])(window); // jshint ignore:line
360
+ }
361
+
362
+ // Remember we already ran scripts for this svg
363
+ ranScripts[imgUrl] = true;
364
+ }
365
+
366
+ // :WORKAROUND:
367
+ // IE doesn't evaluate <style> tags in SVGs that are dynamically added to the page.
368
+ // This trick will trigger IE to read and use any existing SVG <style> tags.
369
+ //
370
+ // Reference: https://github.com/iconic/SVGInjector/issues/23
371
+ var styleTags = svg.querySelectorAll('style');
372
+ forEach.call(styleTags, function (styleTag) {
373
+ styleTag.textContent += '';
374
+ });
375
+
376
+ // Replace the image with the svg
377
+ el.parentNode.replaceChild(svg, el);
378
+
379
+ // Now that we no longer need it, drop references
380
+ // to the original element so it can be GC'd
381
+ delete injectedElements[injectedElements.indexOf(el)];
382
+ el = null;
383
+
384
+ // Increment the injected count
385
+ injectCount++;
386
+
387
+ callback(svg);
388
+ });
389
+ };
390
+
391
+ /**
392
+ * SVGInjector
393
+ *
394
+ * Replace the given elements with their full inline SVG DOM elements.
395
+ *
396
+ * :NOTE: We are using get/setAttribute with SVG because the SVG DOM spec differs from HTML DOM and
397
+ * can return other unexpected object types when trying to directly access svg properties.
398
+ * ex: "className" returns a SVGAnimatedString with the class value found in the "baseVal" property,
399
+ * instead of simple string like with HTML Elements.
400
+ *
401
+ * @param {mixes} Array of or single DOM element
402
+ * @param {object} options
403
+ * @param {function} callback
404
+ * @return {object} Instance of SVGInjector
405
+ */
406
+ var SVGInjector = function (elements, options, done) {
407
+
408
+ // Options & defaults
409
+ options = options || {};
410
+
411
+ // Should we run the scripts blocks found in the SVG
412
+ // 'always' - Run them every time
413
+ // 'once' - Only run scripts once for each SVG
414
+ // [false|'never'] - Ignore scripts
415
+ var evalScripts = options.evalScripts || 'always';
416
+
417
+ // Location of fallback pngs, if desired
418
+ var pngFallback = options.pngFallback || false;
419
+
420
+ // Callback to run during each SVG injection, returning the SVG injected
421
+ var eachCallback = options.each;
422
+
423
+ // Do the injection...
424
+ if (elements.length !== undefined) {
425
+ var elementsLoaded = 0;
426
+ forEach.call(elements, function (element) {
427
+ injectElement(element, evalScripts, pngFallback, function (svg) {
428
+ if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
429
+ if (done && elements.length === ++elementsLoaded) done(elementsLoaded);
430
+ });
431
+ });
432
+ }
433
+ else {
434
+ if (elements) {
435
+ injectElement(elements, evalScripts, pngFallback, function (svg) {
436
+ if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
437
+ if (done) done(1);
438
+ elements = null;
439
+ });
440
+ }
441
+ else {
442
+ if (done) done(0);
443
+ }
444
+ }
445
+ };
446
+
447
+ /* global module, exports: true, define */
448
+ // Node.js or CommonJS
449
+ if (typeof module === 'object' && typeof module.exports === 'object') {
450
+ module.exports = exports = SVGInjector;
451
+ }
452
+ // AMD support
453
+ else if (typeof define === 'function' && define.amd) {
454
+ define(function () {
455
+ return SVGInjector;
456
+ });
457
+ }
458
+ // Otherwise, attach to window as global
459
+ else if (typeof window === 'object') {
460
+ window.SVGInjector = SVGInjector;
461
+ }
462
+ /* global -module, -exports, -define */
463
+
464
+ }(window, document));