tiny_mce_plugin_imageselector 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/LICENSE +22 -0
  2. data/README.rdoc +24 -0
  3. data/lib/assets/plugins/imageselector/LICENSE +22 -0
  4. data/lib/assets/plugins/imageselector/README.md +29 -0
  5. data/lib/assets/plugins/imageselector/css/media_selector.css +80 -0
  6. data/lib/assets/plugins/imageselector/dialog.htm +48 -0
  7. data/lib/assets/plugins/imageselector/editor_plugin.js +1 -0
  8. data/lib/assets/plugins/imageselector/editor_plugin_src.js +81 -0
  9. data/lib/assets/plugins/imageselector/img/example.gif +0 -0
  10. data/lib/assets/plugins/imageselector/img/imageselector.png +0 -0
  11. data/lib/assets/plugins/imageselector/img/spinner.gif +0 -0
  12. data/lib/assets/plugins/imageselector/js/media_selector.js +562 -0
  13. data/lib/assets/plugins/imageselector/js/sammy-0.7.0.min.js +5 -0
  14. data/lib/assets/plugins/imageselector/js/sammy.handlebars-0.7.0.min.js +5 -0
  15. data/lib/assets/plugins/imageselector/js/sammy.template-0.7.0.min.js +5 -0
  16. data/lib/assets/plugins/imageselector/langs/en.js +4 -0
  17. data/lib/assets/plugins/imageselector/langs/en_dlg.js +4 -0
  18. data/lib/assets/plugins/imageselector/templates/no_results.hb +1 -0
  19. data/lib/assets/plugins/imageselector/templates/oembed_failed.rb +1 -0
  20. data/lib/assets/plugins/imageselector/templates/result.hb +18 -0
  21. data/lib/assets/plugins/imageselector/templates/result_thumbnail.hb +5 -0
  22. data/lib/assets/plugins/imageselector/templates/results_failed.hb +1 -0
  23. data/lib/assets/plugins/imageselector/templates/selection.hb +14 -0
  24. data/lib/assets/plugins/imageselector/templates/sizes_failed.rb +1 -0
  25. data/lib/assets/plugins/imageselector/templates/source.hb +1 -0
  26. data/lib/assets/plugins/imageselector/templates/source_next_page_link.hb +1 -0
  27. data/lib/assets/plugins/imageselector/templates/source_next_page_link_search.hb +6 -0
  28. data/lib/assets/plugins/imageselector/templates/source_search.hb +9 -0
  29. data/lib/assets/plugins/imageselector/templates/source_selected.hb +1 -0
  30. data/lib/assets/plugins/imageselector/templates/source_selected_search.hb +9 -0
  31. data/lib/assets/plugins/imageselector/templates/upload.hb +1 -0
  32. data/lib/tiny_mce_plugin_imageselector.rb +23 -0
  33. data/tiny_mce_plugin_imageselector.gemspec +15 -0
  34. metadata +100 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 2011 Horowhenua Library Trust
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,24 @@
1
+ = TinyMCE Plugin ImageSelector
2
+
3
+ This gem uses the tiny_mce gem's plugin system to install the https://github.com/kete/image_selector_tinymce_plugin plugin.
4
+
5
+ = Usage
6
+
7
+ To use this plugin, clone the source, gem build, gem install, and add the following after the tiny_mce gem config line:
8
+
9
+ config.gem 'tiny_mce' # if you haven't done so already
10
+ config.gem 'tiny_mce_plugin_imageselector'
11
+
12
+ You'll want to adjust your config/tiny_mce.yml file to take advantage of the plugin.
13
+
14
+ The imageselector plugin assumes that your site has imageselector config files at /javascripts/image_selector_config/. See the README at https://github.com/kete/image_selector_tinymce_plugin/ for more details on how they are set up.
15
+
16
+ = Credits
17
+
18
+ tiny_mce_plugin_imageselector was created for the Kete project (http://kete.net.nz) and is maintained by Walter McGinnis <walter a-t katipo dot co dot nz>.
19
+
20
+ = License
21
+
22
+ tiny_mce_plugin_imageselector is covered by the MIT License. See LICENSE for more information.
23
+
24
+ Copyright (C) 2011 Horowhenua Library Trust
@@ -0,0 +1,22 @@
1
+ Copyright (C) 2011 Horowhenua Library Trust
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # image_selector_tinymce_plugin
2
+
3
+ ## Description
4
+
5
+ Based on media_selector (https://github.com/kete/media_selector) JavaScript mini-application. See media_selector's README for dependencies, etc.
6
+
7
+ Image Selector is a jQuery and Sammy.js based mini-application for choosing from a list of providers' media assets (images in this case) that integrates into TinyMCE editor as a plugin.
8
+
9
+ Because of its dependency on jQuery, it doesn't currently work with TinyMCE's i18n translation scheme. See http://www.tinymce.com/forum/viewtopic.php?id=16761 for details. Hopefully this issue will be resolved in the future. In the meantime, translate_i18n is set to false.
10
+
11
+ ## Installation
12
+
13
+ Copy the contents of this directory to directory called imageselector under your TinyMCE install's plugins director. Configure TinyMCE to use it via the init declaration.
14
+
15
+ You'll also need to set up JSON files for your image providers and the size you want. IMPORTANT! These are assumed to be under /javascripts/image_selector_config/ on your site. See https://github.com/kete/media_selector/blob/master/data/providers.json and https://github.com/kete/media_selector/blob/master/data/sizes.json for how (you'll need to adjust URLs, etc. to suit).
16
+
17
+ ## Dependencies
18
+
19
+ TinyMCE provides the plugin API that we are integrating with.
20
+
21
+ jQuery (through a link to Google's CDN), Handlebars.js, and Sammy.js along with some Sammy.js plugins that are included in the javascripts directory.
22
+
23
+ ## Author
24
+
25
+ image_selector_tinymce_plugin was created for the Kete project (http://kete.net.nz) and is maintained by Walter McGinnis <walter a-t katipo dot co dot nz>.
26
+
27
+ ## License
28
+
29
+ image_selector_tinymce_plugin is covered by the MIT License. See LICENSE for more information.
@@ -0,0 +1,80 @@
1
+ body {
2
+ font-family: sans-serif;
3
+ }
4
+
5
+ #providers {
6
+ float: left;
7
+ width: 30%;
8
+ }
9
+
10
+ #providers ul {
11
+ padding-left: 0;
12
+ margin-left: 0;
13
+ }
14
+
15
+ #providers li.upload-link {
16
+ list-style-type: none;
17
+ }
18
+
19
+ #providers li.source {
20
+ list-style-type: none;
21
+ }
22
+
23
+ #providers li.source-selected {
24
+ list-style-type: none;
25
+ }
26
+
27
+ #results {
28
+ border-left: #999 1px solid;
29
+ padding-left: 5%;
30
+ float: right;
31
+ width: 65%;
32
+ }
33
+
34
+ #results li.result-grid {
35
+ float: left;
36
+ margin: 5px;
37
+ list-style-type:none;
38
+ width: 250px;
39
+ }
40
+
41
+ .result-thumbnail-select {
42
+ display: none;
43
+ text-align: center;
44
+ }
45
+
46
+ a.result-size-choose {
47
+ text-align: center;
48
+ }
49
+
50
+ li.size-choice {
51
+ float: left;
52
+ margin: 5px;
53
+ list-style-type:none;
54
+ }
55
+
56
+ div.size-name {
57
+ text-transform: capitalize;
58
+ }
59
+
60
+ #home-link {
61
+ clear: both;
62
+ }
63
+
64
+ textarea.selection-embed {
65
+ width: 600px;
66
+ height: 120px;
67
+ border: 3px solid #cccccc;
68
+ padding: 5px;
69
+ }
70
+
71
+ img.spinner {
72
+ display: block;
73
+ margin-left: auto;
74
+ margin-right: auto;
75
+ }
76
+
77
+ #next-page, #search-form-next {
78
+ clear: both;
79
+ width: 100%;
80
+ }
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <title>Select image</title>
5
+
6
+ <link rel="stylesheet" type="text/css" href="css/media_selector.css" />
7
+
8
+ <script type="text/javascript" src="../../tiny_mce_popup.js?v={tinymce_version}"></script>
9
+
10
+ </head>
11
+ <body>
12
+
13
+ <div id="main">
14
+
15
+ <div id="providers">
16
+ <div id="providers-spinner" style="display: none"><img class="spinner" src="img/spinner.gif" width="16" height="16" alt="loading indicator. "></div>
17
+ </div>
18
+
19
+ <div id="results">
20
+ <h2 class="section-header"></h2>
21
+ <div id="results-spinner" style="display: none"><img class="spinner" src="img/spinner.gif" width="16" height="16" alt="loading indicator. "></div>
22
+ </div>
23
+
24
+ <div style="clear:both;"></div>
25
+ </div>
26
+
27
+ <div id="page-spinner"><img class="spinner" src="img/spinner.gif" width="16" height="16" alt="loading indicator. "></div>
28
+
29
+ <div class="mceActionPanel">
30
+ <input type="button" id="cancel" name="cancel" value="cancel" onclick="tinyMCEPopup.close();" />
31
+ </div>
32
+
33
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
34
+
35
+ <script type="text/javascript">
36
+ jQuery.noConflict();
37
+ var mediaSelectorConfig = { directory: '/javascripts/image_selector_config/' };
38
+ </script>
39
+
40
+ <script src="js/sammy-0.7.0.min.js"></script>
41
+ <script src="js/sammy.template-0.7.0.min.js"></script>
42
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0.beta2/handlebars.min.js"></script>
43
+ <script src="js/sammy.handlebars-0.7.0.min.js"></script>
44
+
45
+ <script src="js/media_selector.js"></script>
46
+
47
+ </body>
48
+ </html>
@@ -0,0 +1 @@
1
+ (function(){tinymce.PluginManager.requireLangPack('imageselector');tinymce.create('tinymce.plugins.ImageselectorPlugin',{init:function(ed,url){ed.addCommand('mceImageselector',function(){ed.windowManager.open({file:url+'/dialog.htm',width:900+parseInt(ed.getLang('imageselector.delta_width',0)),height:500+parseInt(ed.getLang('imageselector.delta_height',0)),inline:1,translate_i18n: false},{plugin_url:url})});ed.addButton('imageselector',{title:'imageselector.desc',cmd:'mceImageselector',image:url+'/img/imageselector.png'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('imageselector',n.nodeName=='IMG')})},createControl:function(n,cm){return null},getInfo:function(){return{longname:'Imageselector plugin',author:'Walter McGinnis',authorurl:'http://waltermcginnis.com',infourl:'https://github.com/kete/image_selector_tinymce_plugin',version:"0.2"}}});tinymce.PluginManager.add('imageselector',tinymce.plugins.ImageselectorPlugin)})();
@@ -0,0 +1,81 @@
1
+ /**
2
+ * editor_plugin_src.js
3
+ *
4
+ * Copyright 2011, Horowhenua Library Trust
5
+ * Released under MIT License, see included LICENSE file
6
+ */
7
+
8
+ (function() {
9
+ // Load plugin specific language pack
10
+ tinymce.PluginManager.requireLangPack('imageselector');
11
+
12
+ tinymce.create('tinymce.plugins.ImageselectorPlugin', {
13
+ /**
14
+ * Initializes the plugin, this will be executed after the plugin has been created.
15
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
16
+ * of the editor instance to intercept that event.
17
+ *
18
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
19
+ * @param {string} url Absolute URL to where the plugin is located.
20
+ */
21
+ init : function(ed, url) {
22
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceImageselector');
23
+ ed.addCommand('mceImageselector', function() {
24
+ ed.windowManager.open({
25
+ file : url + '/dialog.htm',
26
+ width : 900 + parseInt(ed.getLang('imageselector.delta_width', 0)),
27
+ height : 500 + parseInt(ed.getLang('imageselector.delta_height', 0)),
28
+ inline : 1,
29
+ translate_i18n: false
30
+ }, {
31
+ plugin_url : url // Plugin absolute URL
32
+ });
33
+ });
34
+
35
+ // Register imageselector button
36
+ ed.addButton('imageselector', {
37
+ title : 'imageselector.desc',
38
+ cmd : 'mceImageselector',
39
+ image : url + '/img/imageselector.png'
40
+ });
41
+
42
+ // Add a node change handler, selects the button in the UI when a image is selected
43
+ ed.onNodeChange.add(function(ed, cm, n) {
44
+ cm.setActive('imageselector', n.nodeName == 'IMG');
45
+ });
46
+ },
47
+
48
+ /**
49
+ * Creates control instances based in the incomming name. This method is normally not
50
+ * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
51
+ * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
52
+ * method can be used to create those.
53
+ *
54
+ * @param {String} n Name of the control to create.
55
+ * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
56
+ * @return {tinymce.ui.Control} New control instance or null if no control was created.
57
+ */
58
+ createControl : function(n, cm) {
59
+ return null;
60
+ },
61
+
62
+ /**
63
+ * Returns information about the plugin as a name/value array.
64
+ * The current keys are longname, author, authorurl, infourl and version.
65
+ *
66
+ * @return {Object} Name/value array containing information about the plugin.
67
+ */
68
+ getInfo : function() {
69
+ return {
70
+ longname : 'Imageselector plugin',
71
+ author : 'Walter McGinnis',
72
+ authorurl : 'http://waltermcginnis.com',
73
+ infourl : 'https://github.com/kete/image_selector_tinymce_plugin',
74
+ version : "0.2"
75
+ };
76
+ }
77
+ });
78
+
79
+ // Register plugin
80
+ tinymce.PluginManager.add('imageselector', tinymce.plugins.ImageselectorPlugin);
81
+ })();
@@ -0,0 +1,562 @@
1
+ /**
2
+ * media_selector.js
3
+ *
4
+ * Copyright 2011, Horowhenua Library Trust
5
+ * Released under MIT License, see included LICENSE file
6
+ *
7
+ * expects a mediaSelectorConfig object to be defined before this file is run
8
+ * it should look something like this:
9
+ *
10
+ * { directory: path/to/directory/for/config/files/ }
11
+ *
12
+ */
13
+ (function($) {
14
+ var app = $.sammy('#main', function() {
15
+ this.use(Sammy.Handlebars, 'hb');
16
+
17
+ this.helpers({
18
+ stubUrlForResult: function() {
19
+ return document.URL.split('#')[0] + '#/results/'
20
+ },
21
+ providerListIdFor: function(providerIndex) {
22
+ return 'provider-list-' + providerIndex;
23
+ },
24
+ providerTitleIdFor: function(providerIndex) {
25
+ return 'provider-title-' + providerIndex;
26
+ },
27
+ setProviders: function(context) {
28
+ $('#providers-spinner').hide();
29
+
30
+ $.each(context.providers, function(i, provider) {
31
+ $('#providers').append("<h3 class=\"provider-title\" id=\"" + context.providerTitleIdFor(i) + "\">" + provider.title + '</h3>');
32
+ $('#providers').append("<ul id=\"" + context.providerListIdFor(i) + "\"></div>");
33
+ });
34
+ },
35
+ sourceIdFor: function(providerIndex, sourceIndex) {
36
+ return 'source-' + providerIndex + '-' + sourceIndex;
37
+ },
38
+ sourceTemplateStub: 'templates/source'
39
+ });
40
+
41
+ // load providers data for every request
42
+ this.around(function(callback) {
43
+ var context = this;
44
+ this.load(mediaSelectorConfig.directory + 'providers.json')
45
+ .then(function(providers) {
46
+ context.providers = providers;
47
+ })
48
+ .then(callback);
49
+ });
50
+
51
+ // index has two panes; providers with their sources and results for selected source
52
+ // which in index case (none specified) is first source of first provider
53
+ this.get('#/', function(context) {
54
+ // get the results from default_source
55
+ // assumes that first provider's first source isn't a search
56
+ var defaultSource = this.providers[0].sources[0];
57
+
58
+ defaultSource.sourceId = context.sourceIdFor(0, 0);
59
+
60
+ defaultSource['provider_title'] = this.providers[0]['title'];
61
+
62
+ this.trigger('updateSourceTo', defaultSource);
63
+
64
+ this.trigger('updateResultsFor', defaultSource);
65
+ });
66
+
67
+ // results for a give source id
68
+ // selected source indicated in providers source list
69
+ function getSource(context) {
70
+ var idIndexes = context.params['id'].split('-');
71
+ var providerIndex = idIndexes[1],
72
+ sourceIndex = idIndexes[2],
73
+ the_provider = context.providers[providerIndex];
74
+
75
+ // get the results from selected source
76
+ var selectedSource = the_provider.sources[sourceIndex];
77
+
78
+ selectedSource['provider_title'] = the_provider['title'];
79
+
80
+ context.trigger('updateSourceTo', selectedSource);
81
+
82
+ context.trigger('updateResultsFor', selectedSource);
83
+ }
84
+
85
+ // these are the same, except for addition of pagination in route
86
+ this.get('#/:id', function(context) { getSource(context) });
87
+ this.get('#/:id/page/:page_number', function(context) { getSource(context) });
88
+
89
+ // same as above, but target for search form for a source
90
+ function postSearchOfSource(context) {
91
+ var idIndexes = context.params['id'].split('-');
92
+ var providerIndex = idIndexes[1],
93
+ sourceIndex = idIndexes[2],
94
+ the_provider = context.providers[providerIndex];
95
+
96
+ // get the results from selected source
97
+ var selectedSource = the_provider.sources[sourceIndex];
98
+
99
+ selectedSource['provider_title'] = the_provider['title'];
100
+
101
+ context.trigger('updateSourceTo', selectedSource);
102
+
103
+ context.trigger('updateResultsFor', selectedSource);
104
+ }
105
+
106
+ // same except for pagination support
107
+ this.post('#/:id', function(context) { postSearchOfSource(context) });
108
+ this.post('#/:id/page/:page_number', function(context) { postSearchOfSource(context) });
109
+
110
+ // a given result's display
111
+ // show available sizes (based on requests to oembed provider for result id)
112
+ // so user may choose which size
113
+ this.get('#/results/:id', function(context) {
114
+ $('#results').fadeOut();
115
+ $('#providers').fadeOut();
116
+ $('#page-spinner').fadeIn();
117
+
118
+ // params['id'] decodes to normal url, but we need escaped version
119
+ var resultUrl = escape(this.params['id']);
120
+
121
+ var result = {
122
+ url: resultUrl,
123
+ hasAllSizes: false,
124
+ hasSizesError: false,
125
+ render: function(context) {
126
+ this.updateWithNeededSizesThenRender(context);
127
+ },
128
+ updateWithNeededSizesThenRender: function(context) {
129
+ result = this;
130
+
131
+ if (result.hasAllSizes || result.hasSizesError) {
132
+ if (!(result.hasSizeError)) {
133
+ // rearrange result to be an array
134
+ // so we don't need to know about the keys of sizes in the template
135
+ var resultSizes = [],
136
+ resultTitle = '',
137
+ resultAuthor= {};
138
+
139
+ var sizeCount = 0;
140
+
141
+ $.each(sizesNames(context), function(i, sizeName) {
142
+ result[sizeName]["size_name"] = sizeName;
143
+
144
+ var currentSize = {};
145
+
146
+ $.each(context.sizes, function(i, sizeOption) {
147
+ if (sizeName === sizeOption.name) {
148
+ currentSize = sizeOption;
149
+ return false;
150
+ }
151
+ });
152
+
153
+ result[sizeName]["oembed_url"] = encodeURIComponent(result.oembedUrlFor(currentSize));
154
+
155
+ resultSizes.push(result[sizeName]);
156
+
157
+ sizeCount++;
158
+
159
+ if (sizeCount === 1) {
160
+ resultTitle = result[sizeName].title;
161
+
162
+ resultAuthor = {
163
+ url: result[sizeName].author_url,
164
+ name: result[sizeName].author_name
165
+ };
166
+ }
167
+ });
168
+
169
+ var resultForTemplate = {
170
+ result_title: resultTitle,
171
+ result_author_url: resultAuthor.url,
172
+ result_author_name: resultAuthor.name,
173
+ sizes: resultSizes
174
+ };
175
+
176
+ $('#page-spinner').fadeOut();
177
+ // this views takes whole area of page
178
+ context.partial('templates/result.hb', resultForTemplate);
179
+ }
180
+ } else {
181
+ // check sizes that are already complete
182
+ var neededSizes = [];
183
+
184
+ $.each(sizesNames(context), function(i, sizeName) {
185
+ // if undefined for sizeName
186
+ // push to neededSizes
187
+ if (typeof(result[sizeName]) == "undefined") {
188
+ neededSizes.push(sizeName);
189
+ }
190
+ });
191
+
192
+ if (neededSizes.length === 0) {
193
+ // this will complete recursion during next call
194
+ result.hasAllSizes = true;
195
+ result.updateWithNeededSizesThenRender(context);
196
+ } else {
197
+ // get the first in neededSizes
198
+ var nextSizeName = neededSizes.shift();
199
+ size = {};
200
+
201
+ $.each(context.sizes, function(i, sizeOption) {
202
+ if (nextSizeName === sizeOption.name) {
203
+ size = sizeOption;
204
+ return false;
205
+ }
206
+ });
207
+
208
+ // and append what is returned from oembed to result object for that size name
209
+ $.get(result.oembedUrlFor(size))
210
+ .success(function(response) {
211
+ // TODO: make this detect xml or json and parse accordingly
212
+ // TODO: this is limited to same domain only for now, update to handle JSONP
213
+ // probably need to switch to $.ajax and more complete parameters call for jsonp
214
+ result[size.name] = $.parseJSON(response);
215
+
216
+ // scope issue, response is set in calling scope, and not getting set with recursive call
217
+ result.updateWithNeededSizesThenRender(context);
218
+ })
219
+ .error(function() {
220
+ context.log("oembed response failed for " + size.name);
221
+ context.partial('templates/oembed_failed.hb', { oembed_url: oembedUrlFor(size) } );
222
+ // this will break cycle of recursive calls
223
+ result.hasSizesError = true;
224
+ result.updateWithNeededSizesThenRender(context);
225
+ });
226
+ }
227
+ }
228
+ },
229
+ oembedUrlFor: function(size) {
230
+ var oembed_url = result.provider.oembed_endpoint + '?url=' + result.url;
231
+ oembed_url += '&maxwidth=' + size.width;
232
+ oembed_url += '&maxheight=' + size.height;
233
+ return oembed_url;
234
+ }
235
+ };
236
+
237
+ // look up provider oembed endpoint
238
+ // TODO: replace this with something that doesn't iterate through each provider
239
+ $.each(context.providers, function(i, provider) {
240
+ // TODO: make sure this works with IE8
241
+ if (result.url.indexOf(provider.domain) != -1) {
242
+ result["provider"] = provider;
243
+ return false;
244
+ }
245
+ });
246
+
247
+ $.when(sizesLoadedInto(context))
248
+ .then(function() {
249
+ result.render(context)
250
+ });
251
+
252
+ });
253
+
254
+ // this gives selected result and the user's selected size
255
+ // and outputs end result of oembed request for html to embed the result at the selected size
256
+ this.get('#/selections/:id', function(context) {
257
+ $('#result-description-and-sizes').fadeOut();
258
+ $('#page-spinner').fadeIn();
259
+
260
+ // params['id'] decodes to normal url, but we need escaped version
261
+ var oembedUrl = this.params['id'];
262
+
263
+ $.get(oembedUrl)
264
+ .success(function(response) {
265
+ // TODO: make this detect xml or json and parse accordingly
266
+ // TODO: this is limited to same domain only for now, update to handle JSONP
267
+ // probably need to switch to $.ajax and more complete parameters call for jsonp
268
+ var selectionFromResponse = $.parseJSON(response);
269
+
270
+ // add alt value for selection so we can use it in template
271
+ var alt = selectionFromResponse.title;
272
+
273
+ // add a full stop to title for better accessibility
274
+ // start by stripping off trailing spaces for ease our following logic
275
+ alt = alt.replace(/\s+$/g, "");
276
+
277
+ if (alt.charAt( alt.length-1 ) === ".") {
278
+ alt = alt + '. ';
279
+ }
280
+
281
+ selectionFromResponse.alt = alt;
282
+
283
+ // look up matching provider, check for code to call with selectionFromResponse
284
+ var selectionProvider;
285
+
286
+ $.each(context.providers, function(i, provider) {
287
+ // TODO: make sure this works with IE8
288
+ if (oembedUrl.indexOf(provider.domain) != -1) {
289
+ selectionProvider = provider;
290
+ return false;
291
+ }
292
+ });
293
+
294
+ $('#page-spinner').fadeOut();
295
+
296
+ if (selectionProvider !== '' &&
297
+ typeof selectionProvider !== 'undefined' &&
298
+ selectionProvider.insertIntoEditor !== '' &&
299
+ typeof selectionProvider.insertIntoEditor !== 'undefined') {
300
+
301
+ if (selectionProvider.insertIntoEditor.editor !== '' &&
302
+ typeof selectionProvider.insertIntoEditor.editor !== 'undefined') {
303
+
304
+ // TODO: tweak this based on provider.media_type in future
305
+ var valueToInsert = '<img src="' + selectionFromResponse.url + '" width="';
306
+ valueToInsert = valueToInsert + selectionFromResponse.width;
307
+ valueToInsert = valueToInsert + '" height="' + selectionFromResponse.height;
308
+ valueToInsert = valueToInsert + '" alt="' + selectionFromResponse.alt + '"> by <a href="';
309
+ valueToInsert = valueToInsert + selectionFromResponse.author_url + '">' + selectionFromResponse.author_name +'</a>';
310
+
311
+ if (selectionProvider.insertIntoEditor.editor === 'TinyMCE') {
312
+ tinyMCEPopup.editor.execCommand('mceInsertContent', false, valueToInsert);
313
+ tinyMCEPopup.close();
314
+ }
315
+ }
316
+ selectionProvider.processFinal(selectionFromResponse);
317
+
318
+ } else {
319
+ // otherwise we render template
320
+ // this view takes whole of view
321
+ context.partial('templates/selection.hb', selectionFromResponse);
322
+ }
323
+ })
324
+ .error(function() {
325
+ context.log("oembed selection response failed for " + oembedUrl);
326
+ context.partial('templates/oembed_failed.hb', { oembed_url: oembedUrl });
327
+ });
328
+ });
329
+
330
+ function sizesLoadedInto(context) {
331
+ return $.get(mediaSelectorConfig.directory + 'sizes.json')
332
+ .success(function(response) {
333
+ // plain response is probably already json object if parse returns null
334
+ var responseAsJSON = response;
335
+
336
+ if (typeof(responseAsJSON) == 'string' || responseAsJSON === '' || typeof(responseAsJSON) === 'undefined') {
337
+ responseAsJSON = $.parseJSON(response);
338
+ }
339
+
340
+ context.sizes = responseAsJSON;
341
+ })
342
+ .error(function() {
343
+ context.log("response failed");
344
+ context.partial('templates/sizes_failed.hb');
345
+ });
346
+ }
347
+
348
+ function sizesNames(context) {
349
+ var names = [];
350
+ $.each(context.sizes, function(i, size) {
351
+ names.push(size.name);
352
+ });
353
+ return names;
354
+ }
355
+
356
+ // route = #/id (id of source) - in form provider index - source index
357
+ // i.e. 0-1 would be the first provider's second source
358
+ // route = #/id (id of source) + params[search_terms] for searchable source
359
+ // route for results = #/results/id where id is url
360
+ // add to results:
361
+ // or upload image -> requests url for upload and returns to #/results/id
362
+ // or add image URL
363
+ // add to result detail page a "back" button
364
+ this.bind('updateSourceTo', function(e, selectedSource) {
365
+ $('#page-spinner').hide();
366
+ $('#results-list').text('');
367
+ $('h3.no-results-title').hide();
368
+ $('#results-spinner').fadeIn();
369
+
370
+ context = this;
371
+
372
+ var searchTerms = this.params['search_terms'];
373
+
374
+ if ($('h3.provider-title').length === 0) {
375
+ this.setProviders(context);
376
+ }
377
+
378
+ $.each(this.providers, function(i, provider) {
379
+ var providerIndex = i;
380
+ var providerListId = context.providerListIdFor(providerIndex);
381
+
382
+ $('#' + providerListId).text('');
383
+
384
+ $.each(provider.sources, function(i, source) {
385
+ source.sourceId = context.sourceIdFor(providerIndex, i);
386
+
387
+ var appropriate_template = context.sourceTemplateStub;
388
+
389
+ if (selectedSource && source === selectedSource) {
390
+ appropriate_template += '_selected';
391
+ }
392
+
393
+ if (source.searchable_stub) {
394
+ appropriate_template += '_search';
395
+
396
+ if (searchTerms) {
397
+ source.value = searchTerms;
398
+ } else {
399
+ source.value = '';
400
+ }
401
+ }
402
+
403
+ appropriate_template += '.hb';
404
+
405
+ context.render(appropriate_template, source)
406
+ .appendTo("#" + providerListId);
407
+ });
408
+
409
+ // HACK: for some reason when '&target_service=' + targetService is added, handlebars fails to parse {{url}} correctly
410
+ // this worksaround the issue in an ugly fashion
411
+ provider.upload_startpoint['service_target_param'] = '&service_target=' + escape(context.stubUrlForResult());
412
+
413
+ if (typeof(provider.upload_startpoint) != "undefined") {
414
+ context.render('templates/upload.hb', provider.upload_startpoint)
415
+ .appendTo("#" + providerListId);
416
+ }
417
+ });
418
+ });
419
+
420
+ // get each of the entries up to limit
421
+ // render in template for result
422
+ // append to #results
423
+ // animate the results each being added
424
+ this.bind('updateResultsFor', function(e, source) {
425
+ context = this;
426
+
427
+ var searchTerms = this.params['search_terms'],
428
+ pageNumber = this.params['page_number'],
429
+ fullUrl = source.url;
430
+
431
+ if (searchTerms) {
432
+ fullUrl += searchTerms;
433
+ }
434
+
435
+ if (typeof(source['limit_parameter']) !== "undefined" &&
436
+ typeof(source['display_limit']) !== "undefined") {
437
+
438
+ var limit_parameter_adjusted = source.limit_parameter;
439
+
440
+ if (searchTerms) {
441
+ limit_parameter_adjusted = limit_parameter_adjusted.replace(/^\?/, "&");
442
+ }
443
+
444
+ fullUrl += limit_parameter_adjusted + source.display_limit;
445
+
446
+ if (source['page_parameter'] !== '' && typeof(source['page_parameter']) !== "undefined") {
447
+ if (pageNumber === '' || typeof pageNumber === 'undefined') {
448
+ pageNumber = 1;
449
+ }
450
+
451
+ source.nextPage = parseInt(pageNumber) + 1;
452
+ fullUrl += source.page_parameter + pageNumber.toString();
453
+ }
454
+ }
455
+
456
+ var resultRequest = $.get(fullUrl)
457
+ .success(function( response ) {
458
+ $('#results-spinner').hide();
459
+ $('#results-list').text('');
460
+
461
+ var resultsTitle = source.name + ' ' + source.media_type_plural;
462
+
463
+ if (searchTerms) {
464
+ resultsTitle = resultsTitle + ' for "' + searchTerms + '"';
465
+ source.searchTerms = searchTerms;
466
+ }
467
+
468
+ resultsTitle = resultsTitle + '(click to select)';
469
+
470
+ $('#results h2').text(resultsTitle);
471
+
472
+ var itemsLimit = source.display_limit;
473
+ var itemsCount = 0;
474
+
475
+ // items from rss items or atom entries
476
+ // i want image thumbnail src (enclosure or media:thumbnail)
477
+ // title
478
+ // full url (link)
479
+ var items = $(response).find('item');
480
+
481
+ // handle Atom
482
+ if (items.length === 0) {
483
+ items = $(response).find('entry');
484
+ }
485
+
486
+ if (items.length) {
487
+ $('#results').append("<ul id=\"results-list\">");
488
+
489
+ items.each(function() {
490
+ if (itemsCount === itemsLimit) { return false; }
491
+
492
+ var resultThumbnail = $(this).find("thumbnail").attr('url');
493
+
494
+ if (!resultThumbnail || 0 === resultThumbnail.length) {
495
+ // TODO: currently broken
496
+ $(this).find('description').each(function() {
497
+ resultThumbnail = $(this).find('img').attr('src');
498
+ });
499
+ }
500
+
501
+ var resultTitle = $(this).find('title').text();
502
+ var resultLink = $(this).find('link').text();
503
+
504
+ var result = {
505
+ title: resultTitle,
506
+ link: resultLink,
507
+ link_escaped: encodeURIComponent(resultLink),
508
+ thumbnail_url: resultThumbnail
509
+ }
510
+
511
+ context.render('templates/result_thumbnail.hb', result)
512
+ .appendTo('#results-list');
513
+
514
+ itemsCount++;
515
+ });
516
+
517
+ $('#results').append("</ul>");
518
+
519
+ if (source.nextPage !== '' && typeof source.nextPage !== 'undefined') {
520
+ // clear them, if they exist, so we can replace them later
521
+ $('#search-form-next').remove();
522
+ $('#next-page').remove();
523
+
524
+ // if we have less items than display_limit,
525
+ // we don't have any more pages of results
526
+ // if equal, we assume there are more (faulty assumption, but relatively safe)
527
+ if (items.length === source.display_limit) {
528
+ if (searchTerms) {
529
+ context.render('templates/source_next_page_link_search.hb', source)
530
+ .appendTo('#results');
531
+ } else {
532
+ context.render('templates/source_next_page_link.hb', source)
533
+ .appendTo('#results');
534
+ }
535
+ }
536
+ }
537
+ } else {
538
+ context.render('templates/no_results.hb', source)
539
+ .appendTo($('#results'));
540
+ }
541
+ })
542
+ .error(function() {
543
+ $('#results-spinner').hide();
544
+
545
+ // clear them, as they are no longer relevant
546
+ $('#search-form-next').remove();
547
+ $('#next-page').remove();
548
+
549
+ context.render('templates/results_failed.hb', source)
550
+ .appendTo($('#results'));
551
+ });
552
+ });
553
+
554
+
555
+ });
556
+
557
+ $(function() {
558
+ app.run('#/');
559
+ });
560
+
561
+ })(jQuery);
562
+
@@ -0,0 +1,5 @@
1
+ // -- Sammy.js -- /sammy.js
2
+ // http://sammyjs.org
3
+ // Version: 0.7.0
4
+ // Built: 2011-07-30 16:55:53 -0700
5
+ (function(h,j){var p,g="([^/]+)",k=/:([\w\d]+)/g,l=/\?([^#]*)$/,c=function(q){return Array.prototype.slice.call(q)},d=function(q){return Object.prototype.toString.call(q)==="[object Function]"},m=function(q){return Object.prototype.toString.call(q)==="[object Array]"},i=function(q){return decodeURIComponent((q||"").replace(/\+/g," "))},b=encodeURIComponent,f=function(q){return String(q).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},n=function(q){return function(r,s){return this.route.apply(this,[q,r,s])}},a={},o=!!(j.history&&history.pushState),e=[];p=function(){var r=c(arguments),s,q;p.apps=p.apps||{};if(r.length===0||r[0]&&d(r[0])){return p.apply(p,["body"].concat(r))}else{if(typeof(q=r.shift())=="string"){s=p.apps[q]||new p.Application();s.element_selector=q;if(r.length>0){h.each(r,function(t,u){s.use(u)})}if(s.element_selector!=q){delete p.apps[q]}p.apps[s.element_selector]=s;return s}}};p.VERSION="0.7.0";p.addLogger=function(q){e.push(q)};p.log=function(){var q=c(arguments);q.unshift("["+Date()+"]");h.each(e,function(s,r){r.apply(p,q)})};if(typeof j.console!="undefined"){if(d(j.console.log.apply)){p.addLogger(function(){j.console.log.apply(j.console,arguments)})}else{p.addLogger(function(){j.console.log(arguments)})}}else{if(typeof console!="undefined"){p.addLogger(function(){console.log.apply(console,arguments)})}}h.extend(p,{makeArray:c,isFunction:d,isArray:m});p.Object=function(q){return h.extend(this,q||{})};h.extend(p.Object.prototype,{escapeHTML:f,h:f,toHash:function(){var q={};h.each(this,function(s,r){if(!d(r)){q[s]=r}});return q},toHTML:function(){var q="";h.each(this,function(s,r){if(!d(r)){q+="<strong>"+s+"</strong> "+r+"<br />"}});return q},keys:function(q){var r=[];for(var s in this){if(!d(this[s])||!q){r.push(s)}}return r},has:function(q){return this[q]&&h.trim(this[q].toString())!==""},join:function(){var r=c(arguments);var q=r.shift();return r.join(q)},log:function(){p.log.apply(p,arguments)},toString:function(q){var r=[];h.each(this,function(t,s){if(!d(s)||q){r.push('"'+t+'": '+s.toString())}});return"Sammy.Object: {"+r.join(",")+"}"}});p.DefaultLocationProxy=function(r,q){this.app=r;this.is_native=false;this.has_history=o;this._startPolling(q)};p.DefaultLocationProxy.fullPath=function(q){var r=q.toString().match(/^[^#]*(#.+)$/);var s=r?r[1]:"";return[q.pathname,q.search,s].join("")};p.DefaultLocationProxy.prototype={bind:function(){var r=this,s=this.app,q=p.DefaultLocationProxy;h(j).bind("hashchange."+this.app.eventNamespace(),function(u,t){if(r.is_native===false&&!t){r.is_native=true;j.clearInterval(q._interval)}s.trigger("location-changed")});if(o&&!s.disable_push_state){h(j).bind("popstate."+this.app.eventNamespace(),function(t){s.trigger("location-changed")});h("a").live("click.history-"+this.app.eventNamespace(),function(u){var t=q.fullPath(this);if(this.hostname==j.location.hostname&&s.lookupRoute("get",t)){u.preventDefault();r.setLocation(t);return false}})}if(!q._bindings){q._bindings=0}q._bindings++},unbind:function(){h(j).unbind("hashchange."+this.app.eventNamespace());h(j).unbind("popstate."+this.app.eventNamespace());h("a").die("click.history-"+this.app.eventNamespace());p.DefaultLocationProxy._bindings--;if(p.DefaultLocationProxy._bindings<=0){j.clearInterval(p.DefaultLocationProxy._interval)}},getLocation:function(){return p.DefaultLocationProxy.fullPath(j.location)},setLocation:function(q){if(/^([^#\/]|$)/.test(q)){if(o){q="/"+q}else{q="#!/"+q}}if(q!=this.getLocation()){if(o&&/^\//.test(q)){history.pushState({path:q},j.title,q);this.app.trigger("location-changed")}else{return(j.location=q)}}},_startPolling:function(s){var r=this;if(!p.DefaultLocationProxy._interval){if(!s){s=10}var q=function(){var t=r.getLocation();if(typeof p.DefaultLocationProxy._last_location=="undefined"||t!=p.DefaultLocationProxy._last_location){j.setTimeout(function(){h(j).trigger("hashchange",[true])},0)}p.DefaultLocationProxy._last_location=t};q();p.DefaultLocationProxy._interval=j.setInterval(q,s)}}};p.Application=function(q){var r=this;this.routes={};this.listeners=new p.Object({});this.arounds=[];this.befores=[];this.namespace=(new Date()).getTime()+"-"+parseInt(Math.random()*1000,10);this.context_prototype=function(){p.EventContext.apply(this,arguments)};this.context_prototype.prototype=new p.EventContext();if(d(q)){q.apply(this,[this])}if(!this._location_proxy){this.setLocationProxy(new p.DefaultLocationProxy(this,this.run_interval_every))}if(this.debug){this.bindToAllEvents(function(t,s){r.log(r.toString(),t.cleaned_type,s||{})})}};p.Application.prototype=h.extend({},p.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error","check-form-submission","redirect","location-changed"],_last_route:null,_location_proxy:null,_running:false,element_selector:"body",debug:false,raise_errors:false,run_interval_every:50,disable_push_state:false,template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(q){return q?h(this.element_selector).find(q):h(this.element_selector)},use:function(){var q=c(arguments),s=q.shift(),r=s||"";try{q.unshift(this);if(typeof s=="string"){r="Sammy."+s;s=p[s]}s.apply(this,q)}catch(t){if(typeof s==="undefined"){this.error("Plugin Error: called use() but plugin ("+r.toString()+") is not defined",t)}else{if(!d(s)){this.error("Plugin Error: called use() but '"+r.toString()+"' is not a function",t)}else{this.error("Plugin Error",t)}}}return this},setLocationProxy:function(q){var r=this._location_proxy;this._location_proxy=q;if(this.isRunning()){if(r){r.unbind()}this._location_proxy.bind()}},route:function(u,r,w){var t=this,v=[],q,s;if(!w&&d(r)){r=u;w=r;u="any"}u=u.toLowerCase();if(r.constructor==String){k.lastIndex=0;while((s=k.exec(r))!==null){v.push(s[1])}r=new RegExp(r.replace(k,g)+"$")}if(typeof w=="string"){w=t[w]}q=function(x){var y={verb:x,path:r,callback:w,param_names:v};t.routes[x]=t.routes[x]||[];t.routes[x].push(y)};if(u==="any"){h.each(this.ROUTE_VERBS,function(y,x){q(x)})}else{q(u)}return this},get:n("get"),post:n("post"),put:n("put"),del:n("delete"),any:n("any"),mapRoutes:function(r){var q=this;h.each(r,function(s,t){q.route.apply(q,t)});return this},eventNamespace:function(){return["sammy-app",this.namespace].join("-")},bind:function(q,s,u){var t=this;if(typeof u=="undefined"){u=s}var r=function(){var x,v,w;x=arguments[0];w=arguments[1];if(w&&w.context){v=w.context;delete w.context}else{v=new t.context_prototype(t,"bind",x.type,w,x.target)}x.cleaned_type=x.type.replace(t.eventNamespace(),"");u.apply(v,[x,w])};if(!this.listeners[q]){this.listeners[q]=[]}this.listeners[q].push(r);if(this.isRunning()){this._listen(q,r)}return this},trigger:function(q,r){this.$element().trigger([q,this.eventNamespace()].join("."),[r]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(q,r){if(d(q)){r=q;q={}}this.befores.push([q,r]);return this},after:function(q){return this.bind("event-context-after",q)},around:function(q){this.arounds.push(q);return this},isRunning:function(){return this._running},helpers:function(q){h.extend(this.context_prototype.prototype,q);return this},helper:function(q,r){this.context_prototype.prototype[q]=r;return this},run:function(q){if(this.isRunning()){return false}var r=this;h.each(this.listeners.toHash(),function(s,t){h.each(t,function(v,u){r._listen(s,u)})});this.trigger("run",{start_url:q});this._running=true;this.last_location=null;if(!(/\#(.+)/.test(this.getLocation()))&&typeof q!="undefined"){this.setLocation(q)}this._checkLocation();this._location_proxy.bind();this.bind("location-changed",function(){r._checkLocation()});this.bind("submit",function(t){var s=r._checkFormSubmission(h(t.target).closest("form"));return(s===false)?t.preventDefault():false});h(j).bind("beforeunload",function(){r.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var q=this;this.trigger("unload");this._location_proxy.unbind();this.$element().unbind("submit").removeClass(q.eventNamespace());h.each(this.listeners.toHash(),function(r,s){h.each(s,function(u,t){q._unlisten(r,t)})});this._running=false;return this},bindToAllEvents:function(r){var q=this;h.each(this.APP_EVENTS,function(s,t){q.bind(t,r)});h.each(this.listeners.keys(true),function(t,s){if(h.inArray(s,q.APP_EVENTS)==-1){q.bind(s,r)}});return this},routablePath:function(q){return q.replace(l,"")},lookupRoute:function(w,u){var v=this,t=false,s=0,q,r;if(typeof this.routes[w]!="undefined"){q=this.routes[w].length;for(;s<q;s++){r=this.routes[w][s];if(v.routablePath(u).match(r.path)){t=r;break}}}return t},runRoute:function(s,F,u,x){var t=this,D=this.lookupRoute(s,F),r,A,v,z,E,B,y,C,q;this.log("runRoute",[s,F].join(" "));this.trigger("run-route",{verb:s,path:F,params:u});if(typeof u=="undefined"){u={}}h.extend(u,this._parseQueryString(F));if(D){this.trigger("route-found",{route:D});if((C=D.path.exec(this.routablePath(F)))!==null){C.shift();h.each(C,function(G,H){if(D.param_names[G]){u[D.param_names[G]]=i(H)}else{if(!u.splat){u.splat=[]}u.splat.push(i(H))}})}r=new this.context_prototype(this,s,F,u,x);v=this.arounds.slice(0);E=this.befores.slice(0);y=[r].concat(u.splat);A=function(){var G;while(E.length>0){B=E.shift();if(t.contextMatchesOptions(r,B[0])){G=B[1].apply(r,[r]);if(G===false){return false}}}t.last_route=D;r.trigger("event-context-before",{context:r});G=D.callback.apply(r,y);r.trigger("event-context-after",{context:r});return G};h.each(v.reverse(),function(G,H){var I=A;A=function(){return H.apply(r,[I])}});try{q=A()}catch(w){this.error(["500 Error",s,F].join(" "),w)}return q}else{return this.notFound(s,F)}},contextMatchesOptions:function(t,v,r){var s=v;if(typeof s==="undefined"||s=={}){return true}if(typeof r==="undefined"){r=true}if(typeof s==="string"||d(s.test)){s={path:s}}if(s.only){return this.contextMatchesOptions(t,s.only,true)}else{if(s.except){return this.contextMatchesOptions(t,s.except,false)}}var q=true,u=true;if(s.path){if(!d(s.path.test)){s.path=new RegExp(s.path.toString()+"$")}q=s.path.test(t.path)}if(s.verb){if(typeof s.verb==="string"){u=s.verb===t.verb}else{u=s.verb.indexOf(t.verb)>-1}}return r?(u&&q):!(u&&q)},getLocation:function(){return this._location_proxy.getLocation()},setLocation:function(q){return this._location_proxy.setLocation(q)},swap:function(q){return this.$element().html(q)},templateCache:function(q,r){if(typeof r!="undefined"){return a[q]=r}else{return a[q]}},clearTemplateCache:function(){return a={}},notFound:function(s,r){var q=this.error(["404 Not Found",s,r].join(" "));return(s==="get")?q:true},error:function(r,q){if(!q){q=new Error()}q.message=[r,q.message].join(" ");this.trigger("error",{message:q.message,error:q});if(this.raise_errors){throw (q)}else{this.log(q.message,q)}},_checkLocation:function(){var q,r;q=this.getLocation();if(!this.last_location||this.last_location[0]!="get"||this.last_location[1]!=q){this.last_location=["get",q];r=this.runRoute("get",q)}return r},_getFormVerb:function(s){var r=h(s),t,q;q=r.find('input[name="_method"]');if(q.length>0){t=q.val()}if(!t){t=r[0].getAttribute("method")}if(!t||t==""){t="get"}return h.trim(t.toString().toLowerCase())},_checkFormSubmission:function(s){var q,t,v,u,r;this.trigger("check-form-submission",{form:s});q=h(s);t=q.attr("action")||"";v=this._getFormVerb(q);this.log("_checkFormSubmission",q,t,v);if(v==="get"){this.setLocation(t+"?"+this._serializeFormParams(q));r=false}else{u=h.extend({},this._parseFormParams(q));r=this.runRoute(v,t,u,s.get(0))}return(typeof r=="undefined")?false:r},_serializeFormParams:function(r){var t="",q=r.serializeArray(),s;if(q.length>0){t=this._encodeFormPair(q[0].name,q[0].value);for(s=1;s<q.length;s++){t=t+"&"+this._encodeFormPair(q[s].name,q[s].value)}}return t},_encodeFormPair:function(q,r){return b(q)+"="+b(r)},_parseFormParams:function(q){var t={},s=q.serializeArray(),r;for(r=0;r<s.length;r++){t=this._parseParamPair(t,s[r].name,s[r].value)}return t},_parseQueryString:function(t){var v={},s,r,u,q;s=t.match(l);if(s){r=s[1].split("&");for(q=0;q<r.length;q++){u=r[q].split("=");v=this._parseParamPair(v,i(u[0]),i(u[1]||""))}}return v},_parseParamPair:function(s,q,r){if(s[q]){if(m(s[q])){s[q].push(r)}else{s[q]=[s[q],r]}}else{s[q]=r}return s},_listen:function(q,r){return this.$element().bind([q,this.eventNamespace()].join("."),r)},_unlisten:function(q,r){return this.$element().unbind([q,this.eventNamespace()].join("."),r)}});p.RenderContext=function(q){this.event_context=q;this.callbacks=[];this.previous_content=null;this.content=null;this.next_engine=false;this.waiting=false};p.RenderContext.prototype=h.extend({},p.Object.prototype,{then:function(s){if(!d(s)){if(typeof s==="string"&&s in this.event_context){var r=this.event_context[s];s=function(t){return r.apply(this.event_context,[t])}}else{return this}}var q=this;if(this.waiting){this.callbacks.push(s)}else{this.wait();j.setTimeout(function(){var t=s.apply(q,[q.content,q.previous_content]);if(t!==false){q.next(t)}},0)}return this},wait:function(){this.waiting=true},next:function(q){this.waiting=false;if(typeof q!=="undefined"){this.previous_content=this.content;this.content=q}if(this.callbacks.length>0){this.then(this.callbacks.shift())}},load:function(q,r,t){var s=this;return this.then(function(){var u,v,x,w;if(d(r)){t=r;r={}}else{r=h.extend({},r)}if(t){this.then(t)}if(typeof q==="string"){x=(q.match(/\.json$/)||r.json);u=((x&&r.cache===true)||r.cache!==false);s.next_engine=s.event_context.engineFor(q);delete r.cache;delete r.json;if(r.engine){s.next_engine=r.engine;delete r.engine}if(u&&(v=this.event_context.app.templateCache(q))){return v}this.wait();h.ajax(h.extend({url:q,data:{},dataType:x?"json":null,type:"get",success:function(y){if(u){s.event_context.app.templateCache(q,y)}s.next(y)}},r));return false}else{if(q.nodeType){return q.innerHTML}if(q.selector){s.next_engine=q.attr("data-engine");if(r.clone===false){return q.remove()[0].innerHTML.toString()}else{return q[0].innerHTML.toString()}}}})},loadPartials:function(q){if(q){this.partials=this.partials||{};for(name in q){this.load(q[name]).then(function(r){this.partials[name]=r})}}return this},render:function(q,s,t,r){if(d(q)&&!s){return this.then(q)}else{return this.loadPartials(r).load(q).interpolate(s,q).then(t)}},partial:function(q,r){return this.render(q,r).swap()},send:function(){var s=this,r=c(arguments),q=r.shift();if(m(r[0])){r=r[0]}return this.then(function(t){r.push(function(u){s.next(u)});s.wait();q.apply(q,r);return false})},collect:function(u,t,q){var s=this;var r=function(){if(d(u)){t=u;u=this.content}var v=[],w=false;h.each(u,function(x,z){var y=t.apply(s,[x,z]);if(y.jquery&&y.length==1){y=y[0];w=true}v.push(y);return y});return w?v:v.join("")};return q?r():this.then(r)},renderEach:function(q,r,s,t){if(m(r)){t=s;s=r;r=null}return this.load(q).then(function(v){var u=this;if(!s){s=m(this.previous_content)?this.previous_content:[]}if(t){h.each(s,function(w,y){var z={},x=this.next_engine||q;r?(z[r]=y):(z=y);t(y,u.event_context.interpolate(v,z,x))})}else{return this.collect(s,function(w,y){var z={},x=this.next_engine||q;r?(z[r]=y):(z=y);return this.event_context.interpolate(v,z,x)},true)}})},interpolate:function(t,s,q){var r=this;return this.then(function(v,u){if(!t&&u){t=u}if(this.next_engine){s=this.next_engine;this.next_engine=false}var w=r.event_context.interpolate(v,t,s,this.partials);return q?u+w:w})},swap:function(){return this.then(function(q){this.event_context.swap(q)}).trigger("changed",{})},appendTo:function(q){return this.then(function(r){h(q).append(r)}).trigger("changed",{})},prependTo:function(q){return this.then(function(r){h(q).prepend(r)}).trigger("changed",{})},replace:function(q){return this.then(function(r){h(q).html(r)}).trigger("changed",{})},trigger:function(q,r){return this.then(function(s){if(typeof r=="undefined"){r={content:s}}this.event_context.trigger(q,r)})}});p.EventContext=function(u,t,r,s,q){this.app=u;this.verb=t;this.path=r;this.params=new p.Object(s);this.target=q};p.EventContext.prototype=h.extend({},p.Object.prototype,{$element:function(){return this.app.$element(c(arguments).shift())},engineFor:function(s){var r=this,q;if(d(s)){return s}s=(s||r.app.template_engine).toString();if((q=s.match(/\.([^\.\?\#]+)$/))){s=q[1]}if(s&&d(r[s])){return r[s]}if(r.app.template_engine){return this.engineFor(r.app.template_engine)}return function(t,u){return t}},interpolate:function(s,t,r,q){return this.engineFor(r).apply(this,[s,t,q])},render:function(q,s,t,r){return new p.RenderContext(this).render(q,s,t,r)},renderEach:function(q,r,s,t){return new p.RenderContext(this).renderEach(q,r,s,t)},load:function(q,r,s){return new p.RenderContext(this).load(q,r,s)},partial:function(q,r){return new p.RenderContext(this).partial(q,r)},send:function(){var q=new p.RenderContext(this);return q.send.apply(q,arguments)},redirect:function(){var y,w=c(arguments),v=this.app.getLocation(),r=w.length;if(r>1){var u=0,z=[],q=[],t={},x=false;for(;u<r;u++){if(typeof w[u]=="string"){z.push(w[u])}else{h.extend(t,w[u]);x=true}}y=z.join("/");if(x){for(var s in t){q.push(this.app._encodeFormPair(s,t[s]))}y+="?"+q.join("&")}}else{y=w[0]}this.trigger("redirect",{to:y});this.app.last_location=[this.verb,this.path];this.app.setLocation(y);if(new RegExp(y).test(v)){this.app.trigger("location-changed")}},trigger:function(q,r){if(typeof r=="undefined"){r={}}if(!r.context){r.context=this}return this.app.trigger(q,r)},eventNamespace:function(){return this.app.eventNamespace()},swap:function(q){return this.app.swap(q)},notFound:function(){return this.app.notFound(this.verb,this.path)},json:function(q){return h.parseJSON(q)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});h.sammy=j.Sammy=p})(jQuery,window);
@@ -0,0 +1,5 @@
1
+ // -- Sammy.js -- /plugins/sammy.handlebars.js
2
+ // http://sammyjs.org
3
+ // Version: 0.7.0
4
+ // Built: 2011-07-30 16:55:44 -0700
5
+ (function(a){Sammy=Sammy||{};Sammy.Handlebars=function(e,c){var d={};var b=function(i,j,g,f){if(typeof f=="undefined"){f=i}var h=d[f];if(!h){h=d[f]=Handlebars.compile(i)}j=a.extend({},this,j);g=a.extend({},j.partials,g);return h(j,{partials:g})};if(!c){c="handlebars"}e.helper(c,b)}})(jQuery);
@@ -0,0 +1,5 @@
1
+ // -- Sammy.js -- /plugins/sammy.template.js
2
+ // http://sammyjs.org
3
+ // Version: 0.7.0
4
+ // Built: 2011-07-30 16:55:51 -0700
5
+ (function(c){var a={};var b=function(e,g,h,d){var f,i;if(a[e]){f=a[e]}else{if(typeof g=="undefined"){return false}if(d&&d.escape_html===false){i='",$1,"'}else{i='",h($1),"'}f=a[e]=new Function("obj",'var ___$$$___=[],print=function(){___$$$___.push.apply(___$$$___,arguments);};with(obj){___$$$___.push("'+String(g).replace(/[\r\t\n]/g," ").replace(/\"/g,'\\"').split("<%").join("\t").replace(/((^|%>)[^\t]*)/g,"$1\r").replace(/\t=(.*?)%>/g,i).replace(/\t!(.*?)%>/g,'",$1,"').split("\t").join('");').split("%>").join('___$$$___.push("').split("\r").join("")+"\");}return ___$$$___.join('');")}if(typeof h!="undefined"){return f(h)}else{return f}};Sammy=Sammy||{};Sammy.Template=function(f,d){var e=function(i,j,h,g){if(typeof h=="undefined"){h=i}if(typeof g=="undefined"&&typeof h=="object"){g=h;h=i}return b(h,i,c.extend({},this,j),g)};if(!d){d="template"}f.helper(d,e)}})(jQuery);
@@ -0,0 +1,4 @@
1
+ // left around for reference, not currently used
2
+ tinyMCE.addI18n('en.imageselector',{
3
+ desc : 'This is just a template button'
4
+ });
@@ -0,0 +1,4 @@
1
+ // left around for reference, not currently used
2
+ tinyMCE.addI18n('en.imageselector_dlg',{
3
+ title : 'This is just a example title'
4
+ });
@@ -0,0 +1 @@
1
+ <h3 id=no-result-{{sourceId}} class="no-results-title">No results for {{name}}</h3>
@@ -0,0 +1 @@
1
+ <h3 id="oembed-failed" class="oembed-failed-title">Unable to load oEmbed for {{oembed_url}}</h3>
@@ -0,0 +1,18 @@
1
+ <div id="result-description-and-sizes">
2
+
3
+ <h2 class="result-title">Title: {{result_title}}</h2>
4
+ <h2 class="result-author">by <a href="{{result_author_url}}" target="_blank">{{result_author_name}}</a></h2>
5
+
6
+ <h1 class="result-size-choice-headline">Choose a size</h1>
7
+
8
+ <ul id="result-sizes">
9
+ {{#sizes}}
10
+ <li class="size-choice" id=result-sizes-{{size_name}}>
11
+ <a href=#/selections/{{oembed_url}} class="result-size-choose"><img src="{{url}}" width="{{width}}" height="{{height}}" class="result-size-image"></a>
12
+ <div class="size-name"><a href=#/selections/{{oembed_url}} class="result-size-choose">{{size_name}}</a></div>
13
+ </li>
14
+ {{/sizes}}
15
+ </ul>
16
+
17
+ <div id="home-link"><a href="index.html">Back to Sources</a></div>
18
+ </div>
@@ -0,0 +1,5 @@
1
+ <li class="result-grid">
2
+ <h4 class="result-thumbnail-title">{{title}} [<a href="{{link}}" target="_blank">view original</a>]</h4>
3
+ <a class="result-thumbnail" href=#/results/{{link_escaped}}><img src="{{thumbnail_url}}" class="result-thumbnail"></a>
4
+ <div class="result-thumbnail-select">Select</a></div>
5
+ </li>
@@ -0,0 +1 @@
1
+ <h3 id=results-failed-{{sourceId}} class="results-failed-title">Results from {{name}} failed to load.</h3>
@@ -0,0 +1,14 @@
1
+ <h1 class="selection-headline">Your selection</h1>
2
+
3
+ <h2 class="selection-title">Title: {{title}}</h2>
4
+ <h2 class="selection-author">by <a href="{{author_url}}" target="_blank">{{author_name}}</a></h2>
5
+
6
+ <img src="{{url}}" width="{{width}}" height="{{height}}" class="selection-image">
7
+
8
+ <div id="embed-details">
9
+ <h3>Embed:</h3>
10
+
11
+ <textarea class="selection-embed"><img src="{{url}}" width="{{width}}" height="{{height}}" alt="{{alt}}"> by <a href="{{author_url}}">{{author_name}}</a></textarea>
12
+
13
+ </div>
14
+ <div id="home-link"><a href="index.html">Back to Sources</a></div>
@@ -0,0 +1 @@
1
+ <h3 id="sizes-failed" class="sizes-failed-title">Unable to load sizes settings.</h3>
@@ -0,0 +1 @@
1
+ <li class="source" id={{sourceId}}><a href=#/{{sourceId}}>{{name}}</a></li>
@@ -0,0 +1 @@
1
+ <div id="next-page"><a href=#/{{sourceId}}/page/{{nextPage}}>More results >></a></div>
@@ -0,0 +1,6 @@
1
+ <div id="search-form-next">
2
+ <form action=#/{{sourceId}}/page/{{nextPage}} method="post">
3
+ <input type="hidden" value="{{searchTerms}}" name="search_terms" />
4
+ <input type="submit" value="More results >>" />
5
+ </form>
6
+ </div>
@@ -0,0 +1,9 @@
1
+ <li class="source" id={{sourceId}}>
2
+ <div class="source-search-form">
3
+ <form action="#/{{sourceId}}" method="post">
4
+ <label>{{name}}:</label>
5
+ <input type="text" size="15" name="search_terms" />
6
+ <input type="submit" value="Go" />
7
+ </form>
8
+ </div>
9
+ </li>
@@ -0,0 +1 @@
1
+ <li class="source source-selected" id={{sourceId}}>{{name}}</li>
@@ -0,0 +1,9 @@
1
+ <li class="source source-selected" id={{sourceId}}>
2
+ <div class="source-search-form">
3
+ <form action="#/{{sourceId}}" method="post">
4
+ <label>{{name}}:</label>
5
+ <input type="text" size="15" name="search_terms" value="{{value}}" />
6
+ <input type="submit" value="Update" />
7
+ </form>
8
+ </div>
9
+ </li>
@@ -0,0 +1 @@
1
+ <li class="upload-link"><a href="{{url}}{{service_target_param}}">{{label}}</li>
@@ -0,0 +1,23 @@
1
+ # Make sure the tiny_mce gem has been loaded before we declare any plugins
2
+ require 'tiny_mce'
3
+
4
+ # We need to make sure that the TinyMCE Editor sources are already in place
5
+ # or any changes we make may be overwritten later, this will return if TinyMCE already initialized
6
+ TinyMCE.initialize
7
+
8
+ # Create the TinyMCE Imageselector Plugin. Inherit from TinyMCE::Plugin which sets a
9
+ # default self.install method, which installs all files in self.assets_path
10
+ # into the public/javascripts/tiny_mce directory
11
+ class TinyMCEImageselector < TinyMCE::Plugin
12
+
13
+ # This lets the TinyMCE::Plugin classes install method know where to find
14
+ # the assets we need to install. If were overwrite the self.install method
15
+ # here, then we don't need to provide this line
16
+ self.assets_path = File.join(File.dirname(__FILE__), 'assets')
17
+
18
+ end
19
+
20
+ # Finally, tell the TinyMCEImageselector Plugin to install itself. The install method
21
+ # can be overwritten in the class definition above. TinyMCE::Plugin provide a
22
+ # default one that will work fine in this example
23
+ TinyMCEImageselector.install
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "tiny_mce_plugin_imageselector"
3
+ s.version = "0.0.2"
4
+ s.authors = ["Walter McGinnis"]
5
+ s.email = "walter@katipo.co.nz"
6
+ s.homepage = "http://github.com/kete/tiny_mce_plugin_imageselector"
7
+ s.summary = "A gem to install the imageselector tiny_mce plugin in tandem with the tinymce gem."
8
+ s.description = "This gem uses the tiny_mce gem's plugin system to install the https://github.com/kete/image_selector_tinymce_plugin plugin."
9
+
10
+ s.files = Dir["lib/**/*", "[A-Z]*", "tiny_mce_plugin_imageselector.gemspec"]
11
+ s.require_path = "lib"
12
+
13
+ s.extra_rdoc_files = Dir["*.rdoc"]
14
+ s.rdoc_options = ["--charset=UTF-8", "--exclude=lib/assets"]
15
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiny_mce_plugin_imageselector
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Walter McGinnis
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-23 00:00:00 +12:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: This gem uses the tiny_mce gem's plugin system to install the https://github.com/kete/image_selector_tinymce_plugin plugin.
23
+ email: walter@katipo.co.nz
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - lib/assets/plugins/imageselector/css/media_selector.css
32
+ - lib/assets/plugins/imageselector/dialog.htm
33
+ - lib/assets/plugins/imageselector/editor_plugin.js
34
+ - lib/assets/plugins/imageselector/editor_plugin_src.js
35
+ - lib/assets/plugins/imageselector/img/example.gif
36
+ - lib/assets/plugins/imageselector/img/imageselector.png
37
+ - lib/assets/plugins/imageselector/img/spinner.gif
38
+ - lib/assets/plugins/imageselector/js/media_selector.js
39
+ - lib/assets/plugins/imageselector/js/sammy-0.7.0.min.js
40
+ - lib/assets/plugins/imageselector/js/sammy.handlebars-0.7.0.min.js
41
+ - lib/assets/plugins/imageselector/js/sammy.template-0.7.0.min.js
42
+ - lib/assets/plugins/imageselector/langs/en.js
43
+ - lib/assets/plugins/imageselector/langs/en_dlg.js
44
+ - lib/assets/plugins/imageselector/LICENSE
45
+ - lib/assets/plugins/imageselector/README.md
46
+ - lib/assets/plugins/imageselector/templates/no_results.hb
47
+ - lib/assets/plugins/imageselector/templates/oembed_failed.rb
48
+ - lib/assets/plugins/imageselector/templates/result.hb
49
+ - lib/assets/plugins/imageselector/templates/result_thumbnail.hb
50
+ - lib/assets/plugins/imageselector/templates/results_failed.hb
51
+ - lib/assets/plugins/imageselector/templates/selection.hb
52
+ - lib/assets/plugins/imageselector/templates/sizes_failed.rb
53
+ - lib/assets/plugins/imageselector/templates/source.hb
54
+ - lib/assets/plugins/imageselector/templates/source_next_page_link.hb
55
+ - lib/assets/plugins/imageselector/templates/source_next_page_link_search.hb
56
+ - lib/assets/plugins/imageselector/templates/source_search.hb
57
+ - lib/assets/plugins/imageselector/templates/source_selected.hb
58
+ - lib/assets/plugins/imageselector/templates/source_selected_search.hb
59
+ - lib/assets/plugins/imageselector/templates/upload.hb
60
+ - lib/tiny_mce_plugin_imageselector.rb
61
+ - LICENSE
62
+ - README.rdoc
63
+ - tiny_mce_plugin_imageselector.gemspec
64
+ has_rdoc: true
65
+ homepage: http://github.com/kete/tiny_mce_plugin_imageselector
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --charset=UTF-8
71
+ - --exclude=lib/assets
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.7
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A gem to install the imageselector tiny_mce plugin in tandem with the tinymce gem.
99
+ test_files: []
100
+