summaryrefslogtreecommitdiff
path: root/www/external/origjs/ng-image-appear.js
blob: e20a65e0664a8997967b947036d9f75a8f110cbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/*
    ng-image-appear v1.11.5
    Copyright (c) 2016 Arun Michael Dsouza (amdsouza92@gmail.com)
    Licence: MIT
    Demo on CodePen - http://codepen.io/amdsouza92/full/aNQeWW/
*/

(function() {
    'use strict';

    // Declaring ngImageAppear module
    var ngImageAppear = angular.module('ngImageAppear', []);

    // Default background color for image wrapper
    var defaultBackgroundColor = '#f0f0f0';

    // ngImageAppear initialization code
    ngImageAppear.run(function() {

        // Creating default stylesheet for elements
        var defaultStylesheet,
            head = document.head;

        // Checking if default stylesheet already exists in DOM
        if(defaultStylesheet === undefined) {
            defaultStylesheet = document.createElement('style');

            // Default CSS stylesheet
            // Styles for elements + animations
            var css = '@animation .ngImageAppearLoader {width: 40px; height: 40px; position: absolute; left: calc((100% - 40px) / 2); top: calc((100% - 40px) / 2);} .ngImageAppearPlaceholder {position: relative; display: inline-block; background-size: cover; background-repeat: no-repeat; background-position: center center; background-color: '+defaultBackgroundColor+';}';
            
            // Adding CSS text to default stylesheet
            defaultStylesheet.appendChild(document.createTextNode(css));

            // Prepend default stylesheet to head 
            head.insertBefore(defaultStylesheet, head.firstChild);
        }
    });

    // ngImageAppear directive 
    ngImageAppear.directive('ngImageAppear',['$timeout', function($timeout) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {

                // Set default CSS classes for elements
                var defaultLoaderClass = 'ngImageAppearLoader',
                    defaultPlaceholderClass = 'ngImageAppearPlaceholder';

                // Fetching element attributes
                var transitionDurationAttr = attrs.transitionDuration, // Set transition duration
                    noLoaderAttr = element[0].hasAttribute('no-loader'), // Check if loader is to be hidden
                    placeholderAttr = attrs.placeholder, // Check if default placeholder image is to be shown
                    placeholderClassAttr = attrs.placeholderClass, // Set CSS class for placeholder (image wrapper)
                    placeholderStyleAttr = attrs.placeholderStyle, // Set CSS styles for placeholder (image wrapper)
                    bgColorAttr = attrs.bgColor, // Set loader wrapper background color
                    loaderImgAttr = attrs.loaderImg, // Set custom loader image
                    loaderClassAttr = attrs.loaderClass, // Set CSS class for loader element
                    loaderStyleAttr = attrs.loaderStyle, // Set custom styles for loader element
                    animationDurationAttr = attrs.animationDuration, // Set animation duration
                    animationAttr = attrs.animation, // Set animation type
                    isResponsiveAttr = element[0].hasAttribute('responsive'), // Check if image is to be set responsive or not
                    easingAttr = attrs.easing; // Set easing for transition/animation

                // Setting default loader attributes
                var loaderSrc = 'data:image/gif;base64,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',
                    defaultPlaceholder = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iNDIuNjVweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgNDIuNjUgMzIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQyLjY1IDMyIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjRDNEM0QzIiBkPSJNMCwwaDQyLjYzN2MwLjAyNCwwLjM1NCwwLjAwNCwwLjcxLDAuMDExLDEuMDY2YzAsMTAuMzEzLDAsMjAuNjI0LDAsMzAuOTM0SDBWMHogTTE1Ljg0OSwxMS41MDINCgkJCWMwLDIuOTYzLTAuMDAyLDUuOTI3LDAuMDAxLDguODkxYzMuNjQ0LDAuMDAzLDcuMjksMC4wMDMsMTAuOTM2LDBjMC4wMDItMi45NjQsMC4wMDItNS45MjcsMC04Ljg5MQ0KCQkJQzIzLjE0MSwxMS40OTgsMTkuNDk1LDExLjQ5OCwxNS44NDksMTEuNTAyeiIvPg0KCTwvZz4NCgk8Zz4NCgkJPHBhdGggZmlsbD0iI0QzRDNEMyIgZD0iTTE2LjUzNywxMi4xODZjMy4xODgsMCw2LjM3NSwwLDkuNTY0LDBjMC4wMDEsMi41MDksMC4wMDEsNS4wMTQtMC4wMDIsNy41MjENCgkJCWMtMy4xODgsMC4wMDMtNi4zNzUsMC4wMDMtOS41NjMsMEMxNi41MzMsMTcuMTk5LDE2LjUzMywxNC42OTQsMTYuNTM3LDEyLjE4NnogTTE3LjIxNSwxMi44N2MwLDIuMDUyLTAuMDAyLDQuMTAzLDAuMDAyLDYuMTU1DQoJCQljMC40NTcsMCwwLjkxNSwwLjAwMywxLjM3My0wLjAwNGMwLjQxLTAuNDA5LDAuODIxLTAuODIxLDEuMjMyLTEuMjMyYzAuMDU2LTAuMDU0LDAuMTA2LTAuMTIxLDAuMTgzLTAuMTQ3DQoJCQljMC42NjUtMC4yMjYsMS4zMzUtMC40NDEsMi0wLjY3MmMwLjIyNi0wLjY4MSwwLjQ1MS0xLjM2MSwwLjY3OS0yLjA0MmMwLjE3OSwwLjM1MiwwLjM1NCwwLjcwNywwLjUzMSwxLjA2MQ0KCQkJYzAuMDY2LDAuMTM1LDAuMTQzLDAuMjY2LDAuMTg4LDAuNDA4YzAuMjA3LDAuNjI2LDAuNDE3LDEuMjUxLDAuNjI1LDEuODc4YzAuMDIxLDAuMDc4LDAuMDg3LDAuMTM0LDAuMTQ1LDAuMTkNCgkJCWMwLjE5LDAuMTg1LDAuMzcxLDAuMzc3LDAuNTY1LDAuNTZjMC4yMjgsMCwwLjQ1MywwLjAwMiwwLjY4MywwYzAuMDAyLTIuMDUyLDAuMDAyLTQuMTAzLDAtNi4xNTUNCgkJCUMyMi42ODYsMTIuODY4LDE5Ljk1LDEyLjg2OCwxNy4yMTUsMTIuODd6Ii8+DQoJPC9nPg0KCTxwYXRoIGZpbGw9IiNEM0QzRDMiIGQ9Ik0xOS4zNzcsMTMuNTgyYzAuNDctMC4xMiwwLjk5NywwLjE0OSwxLjE3NSwwLjU5OWMwLjIwMywwLjQ1NSwwLjAxLDEuMDM2LTAuNDI0LDEuMjc5DQoJCWMtMC40MTgsMC4yNjEtMS4wMTYsMC4xNTEtMS4zMTYtMC4yMzljLTAuMzA0LTAuMzY1LTAuMjk4LTAuOTM5LDAuMDEyLTEuMjk5QzE4Ljk2NSwxMy43NTMsMTkuMTYzLDEzLjYzMiwxOS4zNzcsMTMuNTgyeiIvPg0KPC9nPg0KPC9zdmc+DQo=',           
                    loaderObject = {
                        'className': defaultLoaderClass
                    };

                // Attach CSS class to loader element if attribute is present
                if(loaderClassAttr !== undefined) {
                    loaderObject.className += ' '+loaderClassAttr;
                }

                // Set custom styles for loader element if attribute is present
                if(loaderStyleAttr !== undefined && loaderStyleAttr !== '') {
                    loaderObject.style = loaderStyleAttr;
                } 

                // Setting values for element attributes
                transitionDurationAttr = !transitionDurationAttr ? 0.7+'s' : transitionDurationAttr; // Set transition duration, default - 700ms
                bgColorAttr = !bgColorAttr ? defaultBackgroundColor : bgColorAttr, // Set default bg color for loader wrapper
                animationDurationAttr = !animationDurationAttr ? 0.7+'s' : animationDurationAttr; // Set transition duration, default - 700ms
                easingAttr = !easingAttr ? 'ease-in-out' : easingAttr; // Set easing for transition, default - ease-in-out

                // Set custom loader image if present
                loaderObject.src = loaderImgAttr ? loaderImgAttr : loaderSrc; 

                // DOM manipulation element variable declarations
                var imgElement, 
                    parentElement, 
                    imgWrapper, 
                    loaderElement,
                    wrapperStyles = 'background-color: '+bgColorAttr+'; ',
                    setImageElementWidth,
                    isSmall = false,
                    hasShownLoader = false,
                    animationText;

                // Add placeholder image if attribute is present
                if(placeholderAttr !== undefined) {
                    if(placeholderAttr === '') {
                        // Set default placeholder
                        wrapperStyles += 'background-image: url('+defaultPlaceholder+'); ';
                    }
                    else {
                        // Set custom placeholder
                        wrapperStyles += 'background-image: url('+placeholderAttr+'); ';
                    }
                }

                // Function to render loader
                function renderLoader() {

                    // Show loader in DOM
                    function showLoader() {
                        loaderElement = document.createElement('img'); 

                        // Adding loader object properties to loader element
                        for(var key in loaderObject) {
                            loaderElement[key] = loaderObject[key]; 
                        }

                        // Set loader element's visual styles to null
                        loaderElement.style.margin = loaderElement.style.padding =  loaderElement.style.border = loaderElement.style.borderRadius = 0;
                        loaderElement.style.boxShadow = loaderElement.style.float = 'none'; 
                        loaderElement.style.transform = loaderElement.style.outline = '';

                        // Add loader to DOM
                        imgWrapper.appendChild(loaderElement);
                        hasShownLoader = true;
                    }

                    // Check custom loader image extension
                    if(loaderImgAttr) {

                        // Get filetype of image
                        var fileType = loaderImgAttr.split('.').pop();
                        fileType = fileType.substring(0,3);

                        // Show loader if gif file is present
                        if(fileType === 'gif') {
                            showLoader();
                        }
                        // Else throw warning in console
                        else {
                            console.warn('The custom loader image should have a proper gif extension. Read full documentation here - https://github.com/ArunMichaelDsouza/ng-image-appear');
                        }
                    }
                    else {
                        showLoader();
                    }
                }
                
                // Function to remove loader element from DOM
                function removeLoader() {

                    // Check for loader visibility flags
                    if(!isSmall && !noLoaderAttr && hasShownLoader) {
                        var elementLoader = element[0].nextSibling; // Get loader of current element
                        if(elementLoader) {
                          elementLoader.parentNode.removeChild(elementLoader); // Remove rendered loader from DOM
                        }
                    }
                }

                // Function to remove wrapper element from DOM
                function removeImgWrapper() {

                    // Interval to check that image wrapper has been rendered in DOM
                    var intervalRemove = setInterval(function() {
                        if(imgWrapper !== undefined) {
                            clearInterval(intervalRemove);
                                
                            // Reset img wrapper CSS
                            imgWrapper.style.backgroundColor = imgWrapper.style.position = imgElement.style.width = imgElement.style.padding = imgElement.style.margin = imgElement.style.border = imgElement.style.borderRadius = imgElement.style.boxShadow = imgElement.style.float = imgElement.style.transform = imgElement.style.outline = '';

                            var wrapper = element[0].parentNode,
                                wrapperParent = wrapper.parentNode;
                            wrapperParent.replaceChild(element[0], wrapper); // Replace wrapper with actual image element
                        }
                    }, 1);
                }

                // Function to render image wrapper in DOM
                function renderImageWrapper(imgElementWidth, parentElementWidth, imgElementStyles) {

                    // Append placeholder styles to image wrapper if attribute is present
                    if(placeholderStyleAttr !== undefined && placeholderStyleAttr !== '') {
                        wrapperStyles += placeholderStyleAttr;
                    }

                    imgWrapper = document.createElement('div'); // Create wrapper element for image
                    imgWrapper.setAttribute('style', wrapperStyles); // Set default CSS for wrapper element
                    imgWrapper.className = defaultPlaceholderClass; // Attach default CSS placeholder class to image wrapper

                    // Append placeholder custom class if attribute is present
                    if(placeholderClassAttr !== undefined && placeholderClassAttr !== '') {
                        imgWrapper.className += ' '+placeholderClassAttr;
                    }

                    // Set default CSS width + unit for img element
                    if(isResponsiveAttr) {
                        // Set image element width in %
                        setImageElementWidth = Math.round((imgElementWidth * 100) / parentElementWidth);
                        setImageElementWidth+= '%';

                        // Set wrapper width to width of image element
                        imgWrapper.style.width = setImageElementWidth; 
                    }
                    else {
                        // Set image element width in px
                        setImageElementWidth = Math.round(imgElementWidth);
                        setImageElementWidth+= 'px';

                        // Set wrapper width to width of image element
                        imgWrapper.style.width = setImageElementWidth;
                    }

                    // Add image element styles to wrapper element
                    for(var property in imgElementStyles) {
                        imgWrapper.style[property] = imgElementStyles[property];
                    }

                    imgElement.style.width = '100%'; // Span image element to 100% width of wrapper
                    imgElement.style.padding = imgElement.style.margin = 0; // Set image element's margin/padding to 0

                     //PP
                    //parentElement.replaceChild(imgWrapper, imgElement); // Replace actual image element with wrapper element
                    imgElement.replaceWith(imgWrapper);
                    imgWrapper.appendChild(imgElement); // Append actual image element to wrapper element
                    // This will wrap the image element into a parent div tag used for showing the loader

                    // Show loader if 'no-loader' attribute is not present
                    if(!noLoaderAttr) {
                        var imgWrapperWidth = imgWrapper.offsetWidth;

                        // Show loader if wrapper width is more than 70px
                        imgWrapperWidth >= 70 ? renderLoader() : isSmall = true;
                    }

                    // Create animation sequence if attribute is present
                    if(animationDurationAttr !== undefined && animationDurationAttr !== '') {
                        animationText = animationAttr+' '+animationDurationAttr+' '+easingAttr;
                    }
                }

                // Function to get element's content width (without horizontal padding)
                function getElementContentWidth(element, type) {
                    var styles = window.getComputedStyle(element), // Get computed styles of element
                         padding = parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight); // Get horizontal padding of element

                    // Return content width
                    if(type === 'wrapper') {
                        return element.offsetWidth - padding;
                    }
                    else {
                        return element.offsetWidth;
                    }
                }

                // Function to create image wrapper element
                function generateImageWrapper() {
                    imgElement = element[0], // Get image element
                    parentElement = imgElement.parentNode; // Get parent of image element

                    // Fire interval for checking image's width/height until calculated by DOM
                    var interval = setInterval(function() {

                        // If image element's width and height have been calculated by DOM then clear interval
                        if(imgElement.offsetWidth !== 0 && imgElement.clientHeight !== 0) {
                            clearInterval(interval);

                            // Get image element's visual styles and set it to wrapper element when rendered in DOM
                            var imgElementStyles = {
                                padding: window.getComputedStyle(imgElement).padding,
                                margin: window.getComputedStyle(imgElement).margin,
                                borderRadius: window.getComputedStyle(imgElement).borderRadius,
                                border: window.getComputedStyle(imgElement).border,
                                boxShadow: window.getComputedStyle(imgElement).boxShadow,
                                float: window.getComputedStyle(imgElement).float,
                                transform: window.getComputedStyle(imgElement).transform,
                                outline: window.getComputedStyle(imgElement).outline
                            };

                            // Set content width for parent, image elements
                            var parentElementWidth = getElementContentWidth(parentElement, 'wrapper'),
                                imgElementWidth = getElementContentWidth(element[0], 'image');

                            // Render image wrapper
                            renderImageWrapper(imgElementWidth, parentElementWidth, imgElementStyles);
                        }
                    }, 1);
                }

                // Function to load image into DOM
                function loadImage() {
                    removeLoader(); // Remove loader element once image is loaded

                    removeImgWrapper(); // Remove image wrapper from DOM
                        
                    // Make element appear with transition/animation
                    $timeout(function() {
                        element.css({
                            'transition': ' all '+ transitionDurationAttr +' '+ easingAttr, // Set element transition
                            'opacity': 1, // Show image element in view
                            'animation': animationAttr ? animationText : '' // Set element animation
                        });
                    }, 100); // Timeout to clear stack and rebuild DOM
                }

                // Function to initiate actual image load
                function onImageLoad() {
                    loadImage();
                    element.unbind('load');
                }

                // Function to initialise directive
                function initialize() {

                    // Hide image element from view
                    element.css({
                        'opacity': 0
                    });

                    // Create image wrapper for loader
                    generateImageWrapper();

                    // Check if image element has already been completely downloaded
                    if(element[0].complete) {
                        loadImage();
                    }
                    else {
                        // Else detect image load event
                        element.bind('load', onImageLoad);
                    }
                }

                // Function to get image element's source
                function getImageSrc() {
                    return element[0].getAttribute('src');
                }

                // Attach a watcher to image element's source
                scope.$watch(getImageSrc, function(newSrcValue, oldSrcValue) {

                    // Check if the image element's source has actually changed
                    if(newSrcValue && newSrcValue !== oldSrcValue) {
                        initialize(); // Re-initialise directive
                    }
                    
                });

                // Initialise directive
                initialize();
            }
        };
    }]);
})();