1 // Common parts for angularjs plugins
2 // only one ng-app is allowed
4 var ManifoldApp = angular.module('ManifoldApp', []);
5 ManifoldApp.config(function ($interpolateProvider) {
6 $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
9 ManifoldApp.factory('$exceptionHandler', function () {
10 return function (exception, cause) {
11 console.log(exception.message);
15 ManifoldApp.filter('offset', function() {
16 return function(input, start) {
17 start = parseInt(start, 10);
18 return input.slice(start);
23 // http://alexsexton.com/blog/2010/02/using-inheritance-patterns-to-organize-large-jquery-applications/
24 // We will use John Resig's proposal
26 // http://pastie.org/517177
28 // NOTE: missing a destroy function
30 $.plugin = function(name, object) {
31 $.fn[name] = function(options) {
32 var args = Array.prototype.slice.call(arguments, 1);
33 return this.each(function() {
34 var instance = $.data(this, name);
36 instance[options].apply(instance, args);
38 instance = $.data(this, name, new object(options, this));
45 // * false or undefined or none : no debug
46 // * true : trace all event calls
47 // * [ 'in_progress', 'query_done' ] : would only trace to these events
48 var plugin_debug=false;
49 plugin_debug = [ 'in_progress', 'query_done' ];
51 var Plugin = Class.extend({
53 init: function(options, element) {
54 // Mix in the passed in options with the default options
55 this.options = $.extend({}, this.default_options, options);
57 // Save the element reference, both as a jQuery
58 // reference and a normal reference
59 this.element = element;
60 this.$element = $(element);
61 // programmatically add specific class for publishing events
62 // used in manifold.js for triggering API events
63 if ( ! this.$element.hasClass('pubsub')) this.$element.addClass('pubsub');
65 // return this so we can chain/use the bridge with less code.
69 has_query_handler: function() {
70 return (typeof this.on_filter_added === 'function');
73 // do we need to log API calls ?
74 _is_in : function (obj, arr) {
75 for(var i=0; i<arr.length; i++) {
76 if (arr[i] == obj) return true;
79 _deserves_logging: function (event) {
80 if ( ! plugin_debug ) return false;
81 else if ( plugin_debug === true) return true;
82 else if (this._is_in (event, plugin_debug)) return true;
86 _query_handler: function(prefix, event_type, data) {
87 // We suppose this.query_handler_prefix has been defined if this
88 // callback is triggered
92 event = 'filter_added';
95 event = 'filter_removed';
98 event = 'filter_clear';
101 event = 'field_added';
104 event = 'field_removed';
107 event = 'field_clear';
113 fn = 'on_' + prefix + event;
114 if (typeof this[fn] === 'function') {
115 if (this._deserves_logging (event)) {
116 var classname=this.classname;
117 messages.debug("Plugin._query_handler: calling "+fn+" on "+classname);
119 // call with data as parameter
120 // XXX implement anti loop
125 _record_handler: function(prefix, event_type, record) {
126 // We suppose this.query_handler_prefix has been defined if this
127 // callback is triggered
131 event = 'new_record';
134 event = 'clear_records';
137 event = 'query_in_progress';
140 event = 'query_done';
142 case FIELD_STATE_CHANGED:
143 event = 'field_state_changed';
149 fn = 'on_' + prefix + event;
150 if (typeof this[fn] === 'function') {
151 if (this._deserves_logging (event)) {
152 var classname=this.classname;
153 messages.debug("Plugin._record_handler: calling "+fn+" on "+classname);
155 // call with data as parameter
156 // XXX implement anti loop
161 get_handler_function: function(type, prefix) {
163 return $.proxy(function(e, event_type, record) {
164 return this['_' + type + '_handler'](prefix, event_type, record);
168 listen_query: function(query_uuid, prefix) {
169 // default: prefix = ''
170 prefix = (typeof prefix === 'undefined') ? '' : (prefix + '_');
172 this.$element.on(manifold.get_channel('query', query_uuid), this.get_handler_function('query', prefix));
173 this.$element.on(manifold.get_channel('record', query_uuid), this.get_handler_function('record', prefix));
178 /* Helper functions for naming HTML elements (ID, classes), with support for filters and fields */
181 var ret = this.options.plugin_uuid;
182 for (var i = 0; i < arguments.length; i++) {
183 ret = ret + manifold.separator + arguments[i];
189 if (arguments.length == 0) {
190 return $('#' + this.id());
192 // We make sure to search _inside_ the dom tag of the plugin
193 return $('#' + this.id.apply(this, arguments), this.elmt());
197 elts: function(cls) {
198 return $('.' + cls, this.elmt());
201 id_from_filter: function(filter, use_value) {
202 use_value = typeof use_value !== 'undefined' ? use_value : true;
206 var value = filter[2];
207 var op_str = this.getOperatorLabel(op);
208 var s = manifold.separator;
211 return 'filter' + s + key + s + op_str + s + value;
213 return 'filter' + s + key + s + op_str;
217 str_from_filter: function(filter) {
218 return filter[0] + ' ' + filter[1] + ' ' + filter[2];
221 array_from_id: function(id) {
222 var ret = id.split(manifold.separator);
223 ret.shift(); // remove plugin_uuid at the beginning
227 id_from_field: function(field) {
228 return 'field' + manifold.separator + field;
231 field_from_id: function(id) {
233 if (typeof id === 'string') {
234 array = id.split(manifold.separator);
235 } else { // We suppose we have an array ('object')
238 // array = ['field', FIELD_NAME]
242 id_from_key: function(key_field, value) {
244 return key_field + manifold.separator + this.escape_id(value); //.replace(/\\/g, '');
248 // at some point in time we used to have a helper function named 'flat_id' here
249 // the goals was to sort of normalize id's but it turned out we can get rid of that
250 // in a nutshell, we would have an id (can be urn, hrn, whatever) and
251 // we want to be able to retrieve a DOM element based on that (e.g. a checkbox)
252 // so we did something like <tag id="some-id-that-comes-from-the-db">
253 // and then $("#some-id-that-comes-from-the-db")
254 // however the syntax for that selector prevents from using some characters in id
255 // and so for some of our ids this won't work
256 // instead of 'flattening' we now do this instead
257 // <tag some_id="then!we:can+use.what$we!want">
258 // and to retrieve it
259 // $("[some_id='then!we:can+use.what$we!want']")
260 // which thanks to the quotes, works; and you can use this with id as well in fact
261 // of course if now we have quotes in the id it's going to squeak, but well..
263 // escape (read: backslashes) some meta-chars in input
264 escape_id: function(id) {
265 if( id !== undefined){
266 return id.replace( /(:|\.|\[|\])/g, "\\$1" );
268 return "undefined-id";
272 id_from_record: function(method, record) {
273 var keys = manifold.metadata.get_key(method);
280 switch (Object.toType(key)) {
282 if (!(key in record))
284 return this.id_from_key(key, record[key]);
287 throw 'Not implemented';
291 key_from_id: function(id) {
292 // NOTE this works only for simple keys
295 if (typeof id === 'string') {
296 array = id.split(manifold.separator);
297 } else { // We suppose we have an array ('object')
301 // arguments has the initial id but lacks the key field name (see id_from_key), so we are even
302 // we finally add +1 for the plugin_uuid at the beginning
303 return array[arguments.length + 1];
307 // plugin-helper.js is about managing toggled state
308 // it would be beneficial to merge it in here
309 toggle_on: function () { return this.toggle("true"); },
310 toggle_off: function () { return this.toggle("false"); },
311 toggle: function (status) {
312 plugin_helper.set_toggle_status (this.options.plugin_uuid,status);
316 // use spin() to get our default spin settings (called presets)
317 // use spin(true) to get spin's builtin defaults
318 // you can also call spin_presets() yourself and tweak what you need to, like topmenuvalidation does
319 spin: function (message) {
321 message = 'Please be patient, this operation can take a minute or two.';
323 $('div.loading').fadeIn('fast');
324 $('div.loading').find('.message').text(message);
329 $('div.loading').fadeOut('fast');
335 load_template: function(name, ctx) {
336 return Mustache.render(this.elmt(name).html(), ctx);