decidim-core 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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));