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.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/app/assets/config/decidim_core_manifest.js +1 -0
- data/app/assets/javascripts/decidim.js.es6 +3 -2
- data/app/assets/javascripts/decidim/append_elements.js.es6 +8 -0
- data/app/assets/javascripts/decidim/filters.js.es6 +22 -0
- data/app/assets/javascripts/decidim/form_filter.component.js.es6 +176 -0
- data/app/assets/javascripts/decidim/form_filter.component.test.js +151 -0
- data/app/assets/javascripts/decidim/inline_svg.js.es6 +12 -0
- data/app/assets/javascripts/decidim/user_registrations.js.es6 +22 -0
- data/app/assets/stylesheets/decidim/_variables.scss +1 -1
- data/app/assets/stylesheets/decidim/modules/_comments.scss +3 -6
- data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +22 -0
- data/app/assets/stylesheets/decidim/modules/_layout.scss +9 -1
- data/app/assets/stylesheets/decidim/modules/_navbar.scss +8 -5
- data/app/assets/stylesheets/decidim/modules/_order-by.scss +0 -1
- data/app/assets/stylesheets/decidim/modules/_process-phase.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_timeline.scss +62 -80
- data/app/assets/stylesheets/decidim/modules/_typography.scss +20 -31
- data/app/assets/stylesheets/decidim/utils/_fontface.scss +4 -16
- data/app/assets/stylesheets/decidim/utils/_settings.scss +29 -26
- data/app/assets/stylesheets/decidim/utils/_variables.scss +22 -0
- data/app/commands/decidim/authorize_user.rb +17 -1
- data/app/commands/decidim/create_omniauth_registration.rb +92 -0
- data/app/commands/decidim/create_registration.rb +50 -0
- data/app/commands/decidim/invite_user.rb +50 -0
- data/app/commands/decidim/invite_user_again.rb +25 -0
- data/app/commands/decidim/remove_user_role.rb +26 -0
- data/app/controllers/concerns/decidim/feature_settings.rb +27 -0
- data/app/controllers/concerns/decidim/filter_resource.rb +71 -0
- data/app/controllers/concerns/decidim/form_factory.rb +21 -18
- data/app/controllers/concerns/decidim/needs_participatory_process.rb +2 -3
- data/app/controllers/decidim/devise/confirmations_controller.rb +2 -0
- data/app/controllers/decidim/devise/invitations_controller.rb +4 -0
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +96 -0
- data/app/controllers/decidim/devise/passwords_controller.rb +2 -0
- data/app/controllers/decidim/devise/registrations_controller.rb +34 -0
- data/app/controllers/decidim/devise/sessions_controller.rb +1 -0
- data/app/controllers/decidim/pages_controller.rb +10 -2
- data/app/controllers/decidim/participatory_process_steps_controller.rb +16 -0
- data/app/controllers/decidim/participatory_processes_controller.rb +6 -11
- data/app/forms/decidim/form.rb +6 -6
- data/app/forms/decidim/invite_admin_form.rb +37 -0
- data/app/forms/decidim/omniauth_registration_form.rb +24 -0
- data/app/forms/decidim/registration_form.rb +41 -0
- data/app/helpers/decidim/filters_helper.rb +21 -0
- data/app/helpers/decidim/layout_helper.rb +17 -1
- data/app/helpers/decidim/omniauth_helper.rb +23 -0
- data/app/helpers/decidim/paginate_helper.rb +21 -0
- data/app/helpers/decidim/participatory_process_helper.rb +14 -0
- data/app/helpers/decidim/participatory_process_steps_helper.rb +17 -0
- data/app/mailers/decidim/decidim_devise_mailer.rb +2 -2
- data/app/models/decidim/feature.rb +40 -0
- data/app/models/decidim/identity.rb +12 -0
- data/app/models/decidim/organization.rb +3 -10
- data/app/models/decidim/user.rb +3 -1
- data/app/models/decidim/user_group.rb +18 -0
- data/app/models/decidim/user_group_membership.rb +9 -0
- data/app/services/decidim/authorization_handler.rb +13 -13
- data/app/services/decidim/resource_search.rb +52 -0
- data/app/uploaders/decidim/organization_logo_uploader.rb +1 -1
- data/app/views/decidim/authorizations/new.html.erb +3 -1
- data/app/views/decidim/devise/omniauth_registrations/new.html.erb +40 -0
- data/app/views/decidim/devise/registrations/new.html.erb +21 -1
- data/app/views/decidim/devise/sessions/new.html.erb +1 -0
- data/app/views/decidim/devise/shared/_links.html.erb +0 -8
- data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +21 -0
- data/app/views/decidim/participatory_process_steps/_participatory_process_step.html.erb +16 -0
- data/app/views/decidim/participatory_process_steps/_timeline.html.erb +7 -0
- data/app/views/decidim/participatory_process_steps/index.html.erb +12 -0
- data/app/views/decidim/participatory_processes/show.html.erb +5 -5
- data/app/views/decidim/shared/_login_modal.html.erb +30 -0
- data/app/views/devise/mailer/invite_admin.html.erb +17 -0
- data/app/views/devise/mailer/invite_admin.text.erb +15 -0
- data/app/views/devise/mailer/organization_admin_invitation_instructions.html.erb +1 -1
- data/app/views/devise/mailer/organization_admin_invitation_instructions.text.erb +1 -1
- data/app/views/layouts/decidim/_application.html.erb +1 -0
- data/app/views/layouts/decidim/_header.html.erb +1 -1
- data/app/views/layouts/decidim/_meta.html.erb +1 -0
- data/app/views/layouts/decidim/_process_header.html.erb +12 -1
- data/app/views/layouts/decidim/_process_header_steps.html.erb +1 -0
- data/app/views/layouts/decidim/_social_meta.html.erb +11 -0
- data/app/views/layouts/decidim/participatory_process.html.erb +4 -0
- data/app/views/pages/home.html.erb +29 -2
- data/config/i18n-tasks.yml +1 -0
- data/config/initializers/devise.rb +10 -1
- data/config/locales/ca.yml +45 -3
- data/config/locales/en.yml +45 -3
- data/config/locales/es.yml +45 -3
- data/config/routes.rb +9 -2
- data/config/secrets.yml +36 -0
- data/db/migrate/20170110133113_add_configuration_to_features.rb +7 -0
- data/db/migrate/20170110153807_add_handler_to_organization.rb +5 -0
- data/db/migrate/20170116110851_create_identities.rb +11 -0
- data/db/migrate/20170116135237_loosen_step_requirements.rb +6 -0
- data/db/migrate/20170117142904_add_uniqueness_field_to_authorizations.rb +7 -0
- data/db/migrate/20170119145359_create_user_groups.rb +11 -0
- data/db/migrate/20170119150255_create_user_group_memberships.rb +12 -0
- data/db/migrate/20170119150649_add_show_statistics_to_organization.rb +5 -0
- data/db/migrate/20170120120733_add_user_groups_verified.rb +5 -0
- data/db/seeds.rb +45 -79
- data/lib/decidim/core.rb +8 -0
- data/lib/decidim/core/engine.rb +8 -0
- data/lib/decidim/core/test/factories.rb +188 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/devise_failure_app.rb +1 -0
- data/lib/decidim/feature_manifest.rb +27 -0
- data/lib/decidim/features/base_controller.rb +8 -3
- data/lib/decidim/features/settings_manifest.rb +94 -0
- data/lib/decidim/filter_form_builder.rb +56 -0
- data/lib/decidim/form_builder.rb +4 -7
- data/vendor/assets/javascripts/svg-injector.js +464 -0
- metadata +142 -26
- data/app/assets/stylesheets/decidim/modules/_owl-carousel.scss +0 -72
- data/app/assets/stylesheets/decidim/modules/_phase-nav.scss +0 -177
- data/app/assets/stylesheets/decidim/utils/_helpers.sass +0 -21
- data/app/assets/stylesheets/decidim/utils/_keyframes.sass +0 -13
- data/app/assets/stylesheets/decidim/utils/_mixins.sass +0 -33
data/lib/decidim/form_builder.rb
CHANGED
@@ -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
|
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
|
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 =
|
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));
|